Automation

 View Only
Expand all | Collapse all

Trouble passing a function to be executed with Invoke-VMScript

LucD

LucDMar 24, 2014 06:49 AM

markvm2

markvm2Mar 24, 2014 07:00 AM

  • 1.  Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 02:54 AM

    I have the below function that I need to run on the remote VM through Invoke-VMScript with "remove-profile -days 0 - -computername localhost -profiles $profilename" this script removes a local profile, you can find out more about it here http://gallery.technet.microsoft.com/scriptcenter/Remove-Profile-787d9188

    Now I am having extreme difficultly figuring out how to drop the function with Invoke-VMScript so I can call the function. I usually do "Invoke-VMScript -VM $vmname2 -ScriptText "powershell.exe commands" and it works great, but I can't figure out how to drop a function to that powershell process to call the function. Any ideas? I do not want to do this with a ps1 file or remote share, I want this function to be available to the powershell process i start so I can call it. I have tried a bunch of different things like script blocks and invoke-command but they always break my entire script.

    To make it more clear - When i start a powershell process through Invoke-VMScript, I need this function to be there so I can call it. So once the powershell.exe process is running i can just have it execute "remove-profile -days 0 - -computername localhost -profiles $profilename"

    function remove-profile { [cmdletbinding(

            SupportsShouldProcess = $true,

            ConfirmImpact="High"

        )]

        param(

            [string[]]$computername="localhost",

            [validaterange(0,9999)][int]$days = 1,

            [string[]]$exceptions = $null,

            [string[]]$profiles = $null

        )

        #function to get profiles

        function Get-Profile {

            [cmdletbinding()]

            param(

                [string]$computername,

                [string[]]$exceptions = $null,

                [string[]]$profiles = $null

            )

            #function to convert array of strings into regex for paths to avoid

            function build-Regex {

                param([string[]]$items)

                $( foreach($item in $items){ "^$item$" } ) -join "|"

            }

            $date = get-date

            #test connection

            if(Test-Connection -ComputerName $computername -BufferSize 16 -count 2 -Quiet){

        

                #Check OS

                Try{

                    $opSys = Get-WmiObject Win32_OperatingSystem -computername $computername | select -ExpandProperty version

                }

                Catch{

                    Throw "Error: Could not obtain OS version WMI information from $computername"

                    Return

                }

                #Find XP profiles

                if ($opSys –like “5*”) {

                

                    #define property that we will use to test exceptions / profile regexs against

                    $property = "fullname"

            

                    #get all profiles on computer using file system

                    $allProfiles = Get-Childitem "\\$computername\c$\documents and settings\" -force | ?{$_.PSIsContainer}

                }

                #Find Vista + profiles

                if ($opSys –like “6*”) {

                

                    #define property that we will use to test exceptions / profile regexs against

                    $property = "localpath"

                

                    Try{

                        #get all profiles on computer using WMI

                        $allProfiles = get-wmiobject -computername $computername -class win32_userprofile | ?{ $_.localpath -like "C:\users\*" }

                    }

                    Catch{

                        Throw "Error gathering profile WMI information from $computername.  Be sure that WMI is functioning on this system and that it is running Windows Vista or Server 2008 or later"

                        Return

                    }

                }

                #if specified, filter for profiles

                if($profiles){

                    #build regex using provided profiles

                    $profileRegex = build-Regex $profiles

                    #test profiles against profiles regex

                    $allProfiles = $allProfiles | ?{ $(split-path $_.$property -leaf) -match $profileRegex }

                }

                #if specified, filter exceptions

                if($exceptions){

                    #build regex using provided exceptions

                    $exceptionsRegex = build-Regex $exceptions

                    #test profiles against exceptions regex

                    $allProfiles = $allProfiles | ?{ $(split-path $_.$property -leaf) -notmatch $exceptionsRegex }

                }

                #Return results

                $allProfiles

            }

            else{

                Throw "Could not connect to $computername"

                Return

            }

        }

        #Get date for profile last access comparison

        $date = get-date

        #Add standard accounts to exclude unless explicitly instructed not to

        if( -not $DontExcludeStandardAccounts ){

            $exceptions += "Administrator", "LocalService", "NetworkService", "All Users", "Default User"

        }

        #loop through provided computers

        foreach($computer in $computername){

        

            #get all the profiles for this computer

            $profilesToRemove = Get-Profile -computername $computer -exceptions $exceptions -profiles $profiles -ErrorAction stop

        

            #if none returned, throw an error and move on to the next computer

            if(-not $profilesToRemove){

                Write-Error "Error: No profiles returned on $computer"

                Continue

            }

            #Get-Profiles returns a directoryinfo object for XP, use this to determine OS.

            if($profilesToRemove[0] -isnot [System.IO.DirectoryInfo]){ $opsys = 6 }

            else{ $opsys = 5 }

            #loop through profiles

            foreach($profile in $profilesToRemove){

        

                #Define path and last access time for profile

                if($opsys -eq 6){

                    #Windows 7: convert localpath to remote path remote path.  Currently only handling profiles on C drive

                    $path = $profile.localpath.replace("C:","\\$computer\C$")

                    $lastAccess = ([WMI]'').ConvertToDateTime($profile.LastUseTime)

                }

                else{

                    #Windows XP: define path

                    $path = $profile.fullname

                    $lastAccess = $profile.lastWriteTime

                }

                #Confirm we can reach $path

                Try {

                    get-item $path -force -ErrorAction stop | out-null

                }

                Catch{

                    #if we couldnt get the item, display an error and move on to the next profile

                    Write-Error "Error: Could not get-item for $path"

                    Continue

                }

                #If the profile is older than the days specified, remove it

                if($lastAccess -lt $date.AddDays(-$days)){

            

                    #-confirm and -whatif support

                    if($pscmdlet.shouldprocess("$path last accessed $lastAccess")){

                    

                        #build results object

                        $tempResult = "" | Select ComputerName, Path, lastAccess, Status

                   

                        Try{

                            if($opsys -eq 6){

                                #Windows Vista+: remove the profile using WMI

                                $profile.delete()

                            }

                            else{

                                #Windows XP: remove the profile using file system

                                Remove-Item $path -force -confirm:$false -recurse

                            }

                            #Add properties to results object

                            $tempResult.ComputerName = $computer

                            $tempResult.Path = $path

                            $tempResult.LastAccess = $lastAccess

                            $tempResult.Status = "No error"

                        }

                        Catch{

                        

                            #add properties to results object

                            $tempResult.ComputerName = $computer

                            $tempResult.Path = $path

                            $tempResult.LastAccess = $lastAccess

                            $tempResult.Status = "Error removing profile"

                        

                            #WMI delete method or file removal failed.  Write an error, move on to the next profile

                            Write-Error "Error: Could not delete $path last accessed $lastAccess"

                            Continue

                        }

                    

                        #display result

                        $tempResult

                    }

                }

            }

        }

    }



  • 2.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 05:50 AM

    One way of doing is, is to place the function and the call to the function in a here-string, and then pass that string on the ScriptText parameter.

    $myFunction = @"

    function remove-profile { [cmdletbinding(

    # The rest of the function

    }

    # Call the function

    remove-profile

    "@

    Invoke-VMscript -VM $vm -ScriptText $myFunction -ScriptType PowerShell



  • 3.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:15 AM

    That does not seem to work. The function does not get called, it just seems to spit the text of the string out? in ISE all of the text is brown so I am not sure if that is ok?



  • 4.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:27 AM

    The text is marked as brown in the ISE because the editor sees the complete text as a string (which it is, it is a here-string).

    Try this simplified example

    $myFunction = @"
    function Test-MyFunction {
      "Inside my function"
    }
    Test-MyFunction
    "@


    $vm = Get-VM -Name MyVM
    Invoke-VMScript -VM $vm -ScriptText $myFunction -ScriptType PowerShell

    The output should be something like this



  • 5.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:35 AM

    LucD,

    I am doing just as you described and even tried the example you just gave me. However, it does not execute the function. The script just spits out the text in $myFuction.




  • 6.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:37 AM

    Perhaps you can attach a screenshot ?



  • 7.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:46 AM

    I put that insto a ps1 file and run it. I hope this is not some silly thing and I'm an idiot. I am still new to PS.

    $myFunction = @"

    function Test-MyFunction {

      "Inside my function"

    }

    Test-MyFunction

    "@

    $myFunction

    Read-Host "ok"



  • 8.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:49 AM

    But where is the Invoke-VMScript ?



  • 9.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:51 AM

    I was just testing it out before doing the Invoke-VMScript. It should work the same way right?



  • 10.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:53 AM

    Yes, it should display the text that is inside the function



  • 11.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:56 AM

    Any ideas why it won't? PowerShell version problem? Why would it not work on my system..



  • 12.  RE: Trouble passing a function to be executed with Invoke-VMScript

    Posted Mar 24, 2014 06:59 AM

    But where do you actually run the code ?

    I don't see the PowerShell prompt, nor do I see you calling the .ps1 file.



  • 13.  RE: Trouble passing a function to be executed with Invoke-VMScript