Pablo's Powershell Pow-Wow

Discussion in 'Business & Enterprise Computing' started by PabloEscobar, Sep 18, 2014.

  1. Embercide

    Embercide Member

    Joined:
    Jun 17, 2002
    Messages:
    1,818
    Location:
    Brisbane
    Excel without Excel??

    So I've just spent the afternoon first learning how to get excel cell values and save as variables for a script i'm writing.
    Aaand it's just dawned on me that the PCs this script will run on won't have excel installed :upset::upset:

    Is there some DLL file or something from maybe OpenOffice that I can include with the script so that I can continue as normal?
     
  2. Wynne

    Wynne Member

    Joined:
    Sep 22, 2003
    Messages:
    270
    Location:
    sydney.au
    Probably easier to find a command line tool to convert to CSV and then suck that into PowerShell?

    A quick google turned up quite a few for *nix, one for Windows which still wanted Excel installed (thanks.) and this guy - https://www.coolutils.com/CommandLine/TotalExcelConverter

    Which i've not downloaded or tested and may conscript you to The Suxnet :)
     
  3. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,505
    It's a bad idea in the first place. :)

    http://ramblingcookiemonster.github.io/PSExcel-Intro/

    but that will get you started. - http://ramblingcookiemonster.github.io/ is a great read if you ever have spare time, and want to see useful stuff done in powershell.
     
  4. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,505
    Location:
    Melbourne
    Sorry read this the other day and forgot to reply :)

    I think it was Get-Hotfix, or "Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"

    All good now

    I have managed to get a completed document with nicely formatted tables, and a Table of Contents

    I am still working on some additions that people have asked for, but im pretty happy with it

    Anyone know a good way to list local groups and the users in them

    Most of the ones I have found using wmi seem to try and scan all AD
     
  5. Embercide

    Embercide Member

    Joined:
    Jun 17, 2002
    Messages:
    1,818
    Location:
    Brisbane
    A job for today :)
    Cheers
     
    Last edited: Jun 16, 2016
  6. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    Any ideas on how to set the GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx from the output as a variable, any ideas?
    It'll always be in the same xxx-xxx-xxx format and on the same line

    Script
    Code:
    Write-Host "`n`tEnter onmicrosoft.com domain prefix: " -ForegroundColor Cyan -nonewline;
    $choice = Read-Host
    $domain = $choice
    (Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration|ConvertFrom-Json).token_endpoint.Split('/')

    Output
    Code:
    https:
    
    login.windows.net
    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    oauth2
    token
     
    Last edited: Jun 16, 2016
  7. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,505
    Code:
    (Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration|ConvertFrom-Json).token_endpoint.Split('/')[3]
    will do what you want. Do you understand what it is you are doing?
     
    Last edited: Jun 16, 2016
  8. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    Kinda, I only started using PowerShell like a month ago to help automate all the manual way of doing stuff.

    So I was just missing the [3]

    This seems to be perfect
    Code:
    Write-Host "`n`tEnter onmicrosoft.com domain prefix: " -ForegroundColor Cyan -nonewline;
    $choice = Read-Host
    $domain = $choice
    
    $ID = (Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration|ConvertFrom-Json).token_endpoint.Split('/')[3]
     
  9. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,505
    Breakdown Time

    Code:
    Write-Host "`n`tEnter onmicrosoft.com domain prefix: " -ForegroundColor Cyan -nonewline;
    $choice = Read-Host
    $domain = $choice
    
    This makes Baby Jesus cry. you are writing a prompt. then requesting input and assigning it to a variable ($choice) and then assigning that variable to another variable ($domain)

    Read-Host supports the "prompt" parameter, so this whole thing would be better written as

    Code:
    $Domain = read-host -Prompt "Enter onmicrosoft.com domain prefix"
    
    Same result ($domain is set to whatever the user enters). But much easier to read.

    Code:
    (Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration|ConvertFrom-Json).token_endpoint.Split('/')
    
    This gets ugly quickly, especially if you don't understand what is going in each step.

    First up

    Code:
    Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration
    this is straight forward, it just makes a web request to the URL supplied. if we pipe it to "Get-Member" (we learned about that happy camper near the start of this thread) we can see

    Code:
    Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration | Get-Member
    
       TypeName: Microsoft.PowerShell.Commands.HtmlWebResponseObject
    
    Name              MemberType Definition                                                                 
    ----              ---------- ----------                                                                 
    Equals            Method     bool Equals(System.Object obj)                                             
    GetHashCode       Method     int GetHashCode()                                                          
    GetType           Method     type GetType()                                                             
    ToString          Method     string ToString()                                                          
    AllElements       Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection AllElements {get;}
    BaseResponse      Property   System.Net.WebResponse BaseResponse {get;set;}                             
    Content           Property   string Content {get;}                                                      
    Forms             Property   Microsoft.PowerShell.Commands.FormObjectCollection Forms {get;}            
    Headers           Property   System.Collections.Generic.Dictionary[string,string] Headers {get;}        
    Images            Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Images {get;}     
    InputFields       Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection InputFields {get;}
    Links             Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Links {get;}      
    ParsedHtml        Property   mshtml.IHTMLDocument2 ParsedHtml {get;}                                    
    RawContent        Property   string RawContent {get;}                                                   
    RawContentLength  Property   long RawContentLength {get;}                                               
    RawContentStream  Property   System.IO.MemoryStream RawContentStream {get;}                             
    Scripts           Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Scripts {get;}    
    StatusCode        Property   int StatusCode {get;}                                                      
    StatusDescription Property   string StatusDescription {get;}  
    
    The type, and the properties available to us. the RawContent property contains the data that would normally be parsed by a browser for display.

    Code:
    Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration | Select -expandproperty RawContent
    
    HTTP/1.1 200 OK
    x-ms-request-id: 81dd1f7b-8d25-4103-8614-c17e5e4e4e46
    client-request-id: 09dc9bfd-a298-4a18-923e-4224c2ab2b19
    X-Content-Type-Options: nosniff
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    Cache-Control: private
    Content-Type: application/json; charset=utf-8
    P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
    Set-Cookie: esctx=AAABAAAAiL9Kn2Z27UubvWFPbm0gLU3RL4x1P4rZU7VVkVSjz8vptF3AB7bCTOqfjuMCYVG5ClRhdtsZJLvvnh4Xwxsl8gvQOCyQ9JGrFPsQKfL_xjP6YmGvoT_vsbJGf1SPRjwmvMO1SkvkZrUfO6p6IxWp9U1N2RyZIoxU7ApN-9gN4g0vxNT5O
    vULZhQ3h_MGlezLIAA; domain=.login.windows.net; path=/; secure; HttpOnly,x-ms-gateway-slice=productiona; path=/; secure; HttpOnly,stsservicecookie=ests; path=/; secure; HttpOnly
    Server: Microsoft-IIS/8.5
    X-Powered-By: ASP.NET
    Date: Thu, 16 Jun 2016 03:04:31 GMT
    Content-Length: 1262
    
    {"authorization_endpoint":"https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/authorize","token_endpoint":"https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/token",
    "token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt"],"jwks_uri":"https://login.windows.net/common/discovery/keys","response_modes_supported":["query","fragment","form_post"],"
    subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"http_logout_supported":true,"response_types_supported":["code","id_token","code id_token","token id_token","token"
    ],"scopes_supported":["openid"],"issuer":"https://sts.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/","claims_supported":["sub","iss","aud","exp","iat","auth_time","acr","amr","nonce","email","given_n
    ame","family_name","nickname"],"microsoft_multi_refresh_token":true,"check_session_iframe":"https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/checksession","end_session_endpoint":"htt
    ps://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/logout","userinfo_endpoint":"https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/openid/userinfo","tenant_region_scope":null,
    "cloud_instance_name":"microsoftonline.com"}
    
    Theres a bunch of stuff there that looks like a Json response, and powershell can play with Json nicely. so we can use the convertfrom-json cmdlet to get it into a nicer format to play with

    Code:
    Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration | ConvertFrom-Json
    
    authorization_endpoint                : https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/authorize
    token_endpoint                        : https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/token
    token_endpoint_auth_methods_supported : {client_secret_post, private_key_jwt}
    jwks_uri                              : https://login.windows.net/common/discovery/keys
    response_modes_supported              : {query, fragment, form_post}
    subject_types_supported               : {pairwise}
    id_token_signing_alg_values_supported : {RS256}
    http_logout_supported                 : True
    response_types_supported              : {code, id_token, code id_token, token id_token...}
    scopes_supported                      : {openid}
    issuer                                : https://sts.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/
    claims_supported                      : {sub, iss, aud, exp...}
    microsoft_multi_refresh_token         : True
    check_session_iframe                  : https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/checksession
    end_session_endpoint                  : https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/oauth2/logout
    userinfo_endpoint                     : https://login.windows.net/19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b/openid/userinfo
    tenant_region_scope                   : 
    cloud_instance_name                   : microsoftonline.com
    
    This takes our ugly, raw content, and turns it into a delightful custom object, that we can further molest with our powershell skillz, so we chuck it into a variable for easy reading, and then start to play with the properties to get what we want.

    Code:
    $Response = Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration | ConvertFrom-Json
    
    $Response.TokenEndpoint
    
    The TokenEndpoint property contains the GUID we are interested in, but it also contains a bunch of crap we don't care about, lets see what we can do about it, to do that, we must see what type of object it is.


    Code:
    $Response = Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration | ConvertFrom-Json
    $Response.token_endpoint | Get-Member
    
     [B]TypeName: System.String[/B]
    
    Name             MemberType            Definition                                                                                                                                                          
    ----             ----------            ----------                                                                                                                                                          
    Clone            Method                System.Object Clone(), System.Object ICloneable.Clone()                                                                                                             
    CompareTo        Method                int CompareTo(System.Object value), int CompareTo(string strB), int IComparable.CompareTo(System.Object obj), int IComparable[string].CompareTo(string other)       
    Contains         Method                bool Contains(string value)                                                                                                                                         
    CopyTo           Method                void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)                                                                                   
    EndsWith         Method                bool EndsWith(string value), bool EndsWith(string value, System.StringComparison comparisonType), bool EndsWith(string value, bool ignoreCase, cultureinfo culture) 
    Equals           Method                bool Equals(System.Object obj), bool Equals(string value), bool Equals(string value, System.StringComparison comparisonType), bool IEquatable[string].Equals(stri...
    GetEnumerator    Method                System.CharEnumerator GetEnumerator(), System.Collections.IEnumerator IEnumerable.GetEnumerator(), System.Collections.Generic.IEnumerator[char] IEnumerable[char]...
    GetHashCode      Method                int GetHashCode()                                                                                                                                                   
    GetType          Method                type GetType()                                                                                                                                                      
    GetTypeCode      Method                System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode()                                                                                           
    IndexOf          Method                int IndexOf(char value), int IndexOf(char value, int startIndex), int IndexOf(char value, int startIndex, int count), int IndexOf(string value), int IndexOf(stri...
    IndexOfAny       Method                int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int startIndex), int IndexOfAny(char[] anyOf, int startIndex, int count)                                 
    Insert           Method                string Insert(int startIndex, string value)                                                                                                                         
    IsNormalized     Method                bool IsNormalized(), bool IsNormalized(System.Text.NormalizationForm normalizationForm)                                                                             
    LastIndexOf      Method                int LastIndexOf(char value), int LastIndexOf(char value, int startIndex), int LastIndexOf(char value, int startIndex, int count), int LastIndexOf(string value), ...
    LastIndexOfAny   Method                int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf, int startIndex), int LastIndexOfAny(char[] anyOf, int startIndex, int count)                     
    Normalize        Method                string Normalize(), string Normalize(System.Text.NormalizationForm normalizationForm)                                                                               
    PadLeft          Method                string PadLeft(int totalWidth), string PadLeft(int totalWidth, char paddingChar)                                                                                    
    PadRight         Method                string PadRight(int totalWidth), string PadRight(int totalWidth, char paddingChar)                                                                                  
    Remove           Method                string Remove(int startIndex, int count), string Remove(int startIndex)                                                                                             
    Replace          Method                string Replace(char oldChar, char newChar), string Replace(string oldValue, string newValue)                                                                        
    [B]Split            Method                string[] Split(Params char[] separator), [/B]string[] Split(char[] separator, int count), string[] Split(char[] separator, System.StringSplitOptions options), string...
    StartsWith       Method                bool StartsWith(string value), bool StartsWith(string value, System.StringComparison comparisonType), bool StartsWith(string value, bool ignoreCase, cultureinfo ...
    Substring        Method                string Substring(int startIndex), string Substring(int startIndex, int length)                                                                                      
    ToBoolean        Method                bool IConvertible.ToBoolean(System.IFormatProvider provider)                                                                                                        
    ToByte           Method                byte IConvertible.ToByte(System.IFormatProvider provider)                                                                                                           
    ToChar           Method                char IConvertible.ToChar(System.IFormatProvider provider)                                                                                                           
    ToCharArray      Method                char[] ToCharArray(), char[] ToCharArray(int startIndex, int length)                                                                                                
    ToDateTime       Method                datetime IConvertible.ToDateTime(System.IFormatProvider provider)                                                                                                   
    ToDecimal        Method                decimal IConvertible.ToDecimal(System.IFormatProvider provider)                                                                                                     
    ToDouble         Method                double IConvertible.ToDouble(System.IFormatProvider provider)                                                                                                       
    ToInt16          Method                int16 IConvertible.ToInt16(System.IFormatProvider provider)                                                                                                         
    ToInt32          Method                int IConvertible.ToInt32(System.IFormatProvider provider)                                                                                                           
    ToInt64          Method                long IConvertible.ToInt64(System.IFormatProvider provider)                                                                                                          
    ToLower          Method                string ToLower(), string ToLower(cultureinfo culture)                                                                                                               
    ToLowerInvariant Method                string ToLowerInvariant()                                                                                                                                           
    ToSByte          Method                sbyte IConvertible.ToSByte(System.IFormatProvider provider)                                                                                                         
    ToSingle         Method                float IConvertible.ToSingle(System.IFormatProvider provider)                                                                                                        
    ToString         Method                string ToString(), string ToString(System.IFormatProvider provider), string IConvertible.ToString(System.IFormatProvider provider)                                  
    ToType           Method                System.Object IConvertible.ToType(type conversionType, System.IFormatProvider provider)                                                                             
    ToUInt16         Method                uint16 IConvertible.ToUInt16(System.IFormatProvider provider)                                                                                                       
    ToUInt32         Method                uint32 IConvertible.ToUInt32(System.IFormatProvider provider)                                                                                                       
    ToUInt64         Method                uint64 IConvertible.ToUInt64(System.IFormatProvider provider)                                                                                                       
    ToUpper          Method                string ToUpper(), string ToUpper(cultureinfo culture)                                                                                                               
    ToUpperInvariant Method                string ToUpperInvariant()                                                                                                                                           
    Trim             Method                string Trim(Params char[] trimChars), string Trim()                                                                                                                 
    TrimEnd          Method                string TrimEnd(Params char[] trimChars)                                                                                                                             
    TrimStart        Method                string TrimStart(Params char[] trimChars)                                                                                                                           
    Chars            ParameterizedProperty char Chars(int index) {get;}                                                                                                                                        
    Length           Property              int Length {get;}
    
    Sweet bro, It's already a string, and because it's a string, theres a bunch of Methods we can do to it (in addition to the properties it's got (remember, it's objects (not turtles), all the way down))

    The Split method is the one we want. It splits a string, based on whatever separator we choose, in this case, the slash

    Code:
    $SplitResponse = $Response.token_endpoint.Split("/")
    $SplitResponse
    
    https:
    
    login.windows.net
    19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b
    oauth2
    token
    
    Thats great, it chops up our URI into individual directories, but we only have use for the GUID portion of the URL.

    So we want to use the Fourth value (We count from Zero)

    So

    Code:
    $SplitResonse[3]
    contains the GUID.

    So to pull it all together.

    Code:
    $Domain = read-host -Prompt "Enter onmicrosoft.com domain prefix" #Prompt the User for the Domain, Put it in $Domain
    
    $Response = Invoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration | ConvertFrom-Json #Send the request, convert the incoming Json into something useful
    $SplitResponse = $Response.token_endpoint.Split("/") # Chop up the token_endpoint property
    $Guid = $SplitResponse[3] #Chuck the Guid (The 4th element of the chopped up token_endpoint) into its own variable for future use. 
    
     
    Last edited: Jun 16, 2016
  10. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    An excellent write-up as always.

    I would add that, as this is just splitting on '/' and positionally as well, you could potentially end up with something you don't expect. As such, I'd always validate that you've got the GUID before doing anything.

    Here is two examples for validating this particular GUID (the first all GUIDs, the second this one specifically using regex to match the pattern of hexidecimal characters in the format 8-4-4-4-12).

    Code:
    $string = "19466bbc-56a3-4a31-a2bb-9c85fe5dfc8b"
    
    try
    {
        [System.Guid]::Parse($string) | Out-Null
        Write-Verbose -Message "$string is a valid GUID"
    } 
    catch 
    {
        Write-Verbose -Message "$string is not a valid GUID"
    }
    
    if($string -match '[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')
    {
        Write-Verbose -Message "$string is a valid GUID"
    }
    else
    {
        Write-Verbose -Message "$string is not a valid GUID"
    }
    
     
  11. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    I'll need to digest that a little bit.

    I can see and understand how this works
    Code:
    (Jnvoke-WebRequest https://login.windows.net/$domain.onmicrosoft.com/.well-known/openid-configuration|ConvertFrom-Json).token_endpoint.Split('/')[3]
    Where as your method I see how it works, do I truly understand it? Not really, will have an indepth look after a quick nap.
     
  12. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,505
    It's the same thing.

    The 1-line example you give isn't easy to digest at a glance. you need to look through the line to see what its doing, and where.

    By splitting it out across a couple lines, its easier to understand what is happening in each of the steps (and easier to adjust if you need to).
     
  13. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    I think I got it now.

    New challenge is a script that starts an Azure VM, and RDPs to it once started, runs a script in Powershell and then deallocates the Azure VM once its done.

    Got a 20 odd hour flight to Canada next week, that'll keep me entertained.
     
  14. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,505
    why does it need to RDP to it?
     
  15. person

    person Member

    Joined:
    Mar 7, 2003
    Messages:
    344
    Location:
    Brisbane
    Yes this sounds bizarre... If your deallocating the VM (deleting the public IP and all) then if you just needed to run some code could you instead use something like Azure Service Fabric ?
     
  16. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,505
    Location:
    Melbourne
    Hey All,

    I have an interesting problem

    Im trying to write a script to run the Send\Receive-SmigServerData command on a bunch of drives

    Each of the Send and Receive commands needs to be run on each machine and they have to have a matching password

    I tried to make it run an invoke-command to make the two servers start at the same time, but it complains about the password

    It has to be a securestring, but if I try and create one, they would be different

    Any ideas on creating a secure string which is common to both machines
     
  17. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    I'm a little confused. Can you use the same credentials against both machines? Or does each machine require different credentials?

    If both can be authenticated to with the same credentials, I assume, but can't test, that you could do something like this:
    Code:
    $sourceComputer = 'localhost'
    $destinationComputer = 'localhost'
    $creds = Get-Credential -Message 'Enter credentials to authenticate to servers'
    $password = Read-Host -Prompt 'Enter password to encrypt migration process' -AsSecureString
    Send-SmigServerData -include Data -ComputerName $sourceComputer -SourcePath "c:\users" -DestinationPath "d:\shares\users" -Verbose -password $password
    Invoke-Command -Credential $creds -ScriptBlock {Receive-SmigServerData -password $args[0]} -ArgumentList $password -ComputerName $destinationComputer
    
    Obviously replace localhost and 127.0.0.1 with your computer names.

    If that doesn't work you might need to do something like this:
    Code:
    $sourceComputer = 'localhost'
    $destinationComputer = 'localhost'
    $creds = Get-Credential -Message 'Enter credentials to authenticate to servers'
    $password = Read-Host -Prompt 'Enter password to encrypt migration process' -AsSecureString
    Invoke-Command -Credential $creds -ScriptBlock {Send-SmigServerData -include Data -ComputerName $sourceComputer -SourcePath "c:\users" -DestinationPath "d:\shares\users" -Verbose -password $args[0]} -ArgumentList $password -ComputerName $sourceComputer
    Invoke-Command -Credential $creds -ScriptBlock {Receive-SmigServerData -password $args[0]} -ArgumentList $password -ComputerName $destinationComputer
    
    EDIT: Also I'm not 100% I have the logic of Source and Destination Computer around the right way, but you should be able to sort that out.
     
  18. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    Last edited: Jul 19, 2016
  19. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    Here is a little script I'm working now

    1. Pull list of companies from O365 Partner Admin Center
    2. Pull users from selected company
    3. Generate complex* temporary password
    4. Set password, force change on first login
    5. Pull mobile number from users O365 profile
    6. Reformat the number within the script to what the API accepts
    7. If no number, enter number and set in profile
    8. Send temporary password as SMS

    The complex* password only uses - + = @ as special charters, doesn't use 0 or 1 numbers or I L O to reduce errors when people are reading the password and mix up I with l or something.

    Just need to figure out how to reformat the pulled number properly
    • If there is a country code +61 need to drop the leading 0 on the number
    • If no country code, number can be with or without leading 0
    • Ensure the number is the correct length
    • Spaces don't matter

    The rest of the reading and writing stuff from the user profile is easy enough
    I'll also add a check for users country because Telstra only support Australian numbers for SMS and we use different providers in SE Asia, so the script will use the correct provider automatically.

    Code:
    ## Authenticate as partner
    Connect-MsolService
    
    ## Find the company tenant
    $TenantId = (Get-MsolPartnerContract -All | Out-GridView -Title "Find the customer..." -PassThru).TenantId
    
    ## Find the user
    $User = (Get-MsolUser -TenantId $TenantId -All | Out-GridView -Title "Find the user..." -PassThru).UserPrincipalName
    
    ## Generate complex password
    $length = 12
    $punc = 43..43 + 45..45 + 61..61 + 64..64
    $digits = 50..57
    $letters = 65..72 + 75..75 + 77..77 + 78..78 + 80..90 + 97..104 + 107..107 + 109..109 + 110..110 + 112..122
    $TempPassword = get-random -count 10 `
    -input ($punc + $digits + $letters) |
    % -begin { $aa = $null } `
    -process {$aa += [char]$_} `
    -end {$aa}
    
    ## Set complex password and force user to change on first login
    #Set-MsolUserPassword -TenantId $TenantId –UserPrincipalName $User –NewPassword $TempPassword -ForceChangePassword $True
    
    ## Send to alternative email
    
    ## Capture cellphone number
    Write-Host "`n`tEnter the cellphone number eg. 0400111222 " -ForegroundColor Cyan -nonewline;
    $choice = Read-Host
    $CellNumber = $choice
    
    ## Authenticate to send SMS
    $app_key = "123"
    $app_secret = "123"
    $auth_string = "https://api.telstra.com/v1/oauth/token?client_id=" + $app_key + "&client_secret=" + $app_secret + "&grant_type=client_credentials&scope=SMS"
    $auth_values = Invoke-RestMethod $auth_string
    
    ## Send SMS
    $tel_number = "$CellNumber"
    $token = $auth_values.access_token
    $body = "Here is your new password \n$TempPassword\n\nGo to portal.office.com to login now\n\nIt is case sensitive \nYou'll be asked to change it on first login"
    $sent_message = Invoke-RestMethod "https://api.telstra.com/v1/sms/messages" -ContentType "application/json" -Headers @{"Authorization"="Bearer $token"} -Method Post -Body "{`"to`":`"$tel_number`", `"body`":`"$body`"}"
    $sent_message
    
    ## Display temporary password
    Write-Host "`n`tTemporary password is: $TempPassword" -ForegroundColor Green -NoNewLine
    Write-Host "`n`tPassword is case sensitive, user will be prompted to change on first login"
    * = Complex by Azure AD standards https://azure.microsoft.com/en-us/documentation/articles/active-directory-passwords-policy/
     
    Last edited: Jul 20, 2016
  20. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    So I think you have most of your other requirements done, although I would probably rework them a little...

    I just wrote this quick bit of code to meet the requirements for your phone number issue that I believe you should be able to integrate rather easily. It always ensures you have 10 digits, and it does add a leading zero, even though you said it didn't matter, I prefer consistency.

    Code:
    $o365PhoneNumber = '400 123 456'
    $o365PhoneNumber = '0400123456'
    $o365PhoneNumber = '+61400123456'
    $o365PhoneNumber = $null
    $o365User = "tempUser"
    
    $finalPhoneNumber = $null
    $message = "No valid Phone Number found, please enter a number for $o365User"
    
    
    if($o365PhoneNumber)
    {
        Write-Verbose -Message 'Found Phone number stored in Office 365, removing superfluous spaces'
        $o365PhoneNumber = $o365PhoneNumber -replace '\s+',''
    }
    else
    {
        Write-Warning -Message "$($o365User.toUpper())'s phone number was not retrieved from Office365!"
    }
    
    Write-Verbose -Message "Processing number retrieved from Office 365: $o365PhoneNumber"
    
    switch -regex ($o365PhoneNumber)
    {
        '^\d{10}$' {$finalPhoneNumber = $o365PhoneNumber} #Perfect case scenario 10 digits
        '^[1-9]\d{8}$' {$finalPhoneNumber = "0$o365PhoneNumber"} #9 digits not starting with zero, add a zero in front
        '^\+61\d{9}$' {$finalPhoneNumber = "0$($o365PhoneNumber.TrimStart('+61'))"} #Removes leading +61 and replaces with a leading zero
        Default {do{$finalPhoneNumber = Read-Host -Prompt $message; $message = "Number entered, '$finalPhoneNumber', is invalid, please enter 10 digits" }until($finalPhoneNumber -match '^\d{10}$')}
    }
    
    $finalPhoneNumber
    
    The variable o365PhoneNumber at the top is set multiple times so you can comment out all the various options and test whichever scenario you like.
     

Share This Page

Advertisement: