Powershell - "Invalid assignment expression." error - powershell

I've got a couple things that i'm working on. One of them is sort of an import/export thing i found on here. but i'm getting the following error
PS C:\Users\joeblogs> C:\Users\joeblogs\Scripts\Copy user data.ps1 Invalid assignment expression. The left hand side of an assignment
operator needs to be something that can be assigned to like a variable
or a property. At C:\Users\delpillay\Documents\Scripts\Copy user
data.ps1:16 char:12
+ $username = <<<< gc env:userame
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : InvalidLeftHandSide
I don't know where to start and i'm not sure what to try...
Below is the code:
$destination = "E:\Users\%username%\Backup"
$folder = "Desktop",
#"Downloads",
"Favorites",
"My Documents",
#"Music",
#"Pictures",
#"Videos",
#"AppData\Local\Mozilla",
#"AppData\Local\Google",
#"AppData\Roaming\Mozilla"
######################################
$username = gc env:userame
$userprofile = gc env:userprofile
##$appData = gc env:localAPPDATA
###### Restore data section ######
if ([IO.Directory]::Exists($destination + "\" + $username + "\"))
{
$caption = "Choose Action";
$message = "A backup folder for $username already exists, would you like to restore the data to the local machine?";
$Yes = new-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Yes";
$No = new-Object System.Management.Automation.Host.ChoiceDescription "&No","No";
$choices = [System.Management.Automation.Host.ChoiceDescription[]]($Yes,$No);
$answer = $host.ui.PromptForChoice($caption,$message,$choices,0)
if ($answer -eq 0)
{
write-host -ForegroundColor green "Restoring data to local machine for $username"
foreach ($f in $folder)
{
$currentLocalFolder = $userprofile + "\" + $f
$currentRemoteFolder = $destination + "\" + $username + "\" + $f
write-host -ForegroundColor cyan " $f..."
Copy-Item -ErrorAction silentlyContinue -recurse $currentRemoteFolder $userprofile
if ($f -eq "AppData\Local\Mozilla") { rename-item $currentLocalFolder "$currentLocalFolder.old" }
if ($f -eq "AppData\Roaming\Mozilla") { rename-item $currentLocalFolder "$currentLocalFolder.old" }
if ($f -eq "AppData\Local\Google") { rename-item $currentLocalFolder "$currentLocalFolder.old" }
}
rename-item "$destination\$username" "$destination\$username.restored"
write-host -ForegroundColor green "Restore Complete!"
}
else
{
write-host -ForegroundColor yellow "Aborting process"
exit
}
}
###### Backup Data section ########
#else
{
Write-Host -ForegroundColor green "Outlook is about to close, save any unsaved emails then press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Get-Process | Where { $_.Name -Eq "OUTLOOK" } | Kill
write-host -ForegroundColor green "Backing up data from local machine for $username"
foreach ($f in $folder)
{
$currentLocalFolder = $userprofile + "\" + $f
$currentRemoteFolder = $destination + "\" + $username + "\" + $f
$currentFolderSize = (Get-ChildItem -ErrorAction silentlyContinue $currentLocalFolder -Recurse -Force | Measure-Object -ErrorAction silentlyContinue -Property Length -Sum ).Sum / 1MB
$currentFolderSizeRounded = [System.Math]::Round($currentFolderSize)
write-host -ForegroundColor cyan " $f... ($currentFolderSizeRounded MB)"
Copy-Item -ErrorAction silentlyContinue -recurse $currentLocalFolder $currentRemoteFolder
}
$oldStylePST = [IO.Directory]::GetFiles($appData + "\Microsoft\Outlook", "*.pst")
foreach($pst in $oldStylePST)
{
if ((test-path -path ($destination + "\" + $username + "\Documents\Outlook Files\oldstyle")) -eq 0){new-item -type directory -path ($destination + "\" + $username + "\Documents\Outlook Files\oldstyle") | out-null}
write-host -ForegroundColor yellow " $pst..."
Copy-Item $pst ($destination + "\" + $username + "\Documents\Outlook Files\oldstyle")
}
write-host -ForegroundColor green "Backup complete!"
}

Few observations:
You are not commenting the Favourites and My Documents. If you want to use them then use comma separated directly.
Use this:
$destination = "E:\Users\%username%\Backup"
$folder = "Desktop","Favorites","My Documents"
#"Downloads",
#"Favorites",
#"My Documents",
#"Music",
#"Pictures",
#"Videos",
#"AppData\Local\Mozilla",
#"AppData\Local\Google",
#"AppData\Roaming\Mozilla"
You have missed the n in username:
$username = gc env:username
Donot use gc env:username. Instead directly access them like this below: Completely reframed:
$destination = "E:\Users\%username%\Backup"
$folder = "Desktop","Favorites","My Documents"
#"Downloads",
#"Favorites",
#"My Documents",
#"Music",
#"Pictures",
#"Videos",
#"AppData\Local\Mozilla",
#"AppData\Local\Google",
#"AppData\Roaming\Mozilla"
######################################
$username = $env:username
$userprofile = $env:userprofile
##$appData = gc env:localAPPDATA
These are the major things that have been fixed. Hope it helps you.

Related

How to delete old profiles with script

So I am trying to adapt this code I got from another post for the needs of my current organization. Please see below code:
$Admin = "Administrator","Public","Default","Administrator"
foreach($file in Get-ChildItem C:\Users\)
{
if ($file -in $Admin)
{
Write-Host = "`r`nUser account is" $file ". This is an Administrator Account, it will not be deleted."
}
else
{
Write-Host = "`r`nUser account is" $file ". Checking profiles age..."
$FileDate = (Get-item C:\Users\$file).CreationTime
Write-Host = $FileDate
$TestDate = (Get-Date).addDays(-30)
Write-Host = $TestDate
If ($FileDate -lt $TestDate)
{
Write-Host = "Since" $file "is older than 30 Days (" $FileDate ") it will be deleted."
$UserAccountPath = "C:\\Users\\$file"
$WMIQuery = "SELECT * FROM Win32_UserProfile WHERE localpath = '$UserAccountPath'"
$UserProfile = get-wmiobject win32_userprofile | where localpath -eq c:\\users\\$file
Remove-WmiObject -InputObject "$UserProfile"
}
else
{
Write-Host = "Since File is dated less than 30 days old (" $FileDate ") it will not need to be deleted."
}
}
}
After running this I get the following error:
Remove-WmiObject : Object reference not set to an instance of an object.
At line:28 char:17
+ Remove-WmiObject -InputObject "$UserProfile"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Remove-WmiObject], NullReferenceException
+ FullyQualifiedErrorId : System.NullReferenceException,Microsoft.PowerShell.Commands.RemoveWmiObject
Any help is appreciated.
Basically, the mistake is in this line:
$UserProfile = Get-WmiObject win32_userprofile | Where localpath -EQ c:\\users\\$file
$UserProfile is null, and will always be null, because the equality comparer -eq is looking for an exact match, to put it into perspective:
'C:\some\path' -eq 'C:\\some\\path' # => False
[pscustomobject]#{
localPath = 'C:\some\path'
} | Where-Object localPath -EQ 'C:\\some\\path' # => Null
To fix this, you can do the following:
# $UserAccountPath = "C:\\Users\\$file" // This line is not needed
#
# DirectoryInfo objects have a FullName property for their Absolute Path
$UserProfile = Get-WmiObject win32_userprofile | Where-Object localpath -EQ $file.FullName
Remove-WmiObject -InputObject $UserProfile
$UserProfile = Get-WmiObject win32_userprofile | Where-Object localpath -EQ $file.FullName
$UserProfile.Delete()

get-process - Unable to retrieve some process information and command line

I've 2 questions regarding the code below :
Question 1:
For some unknown reason, the following code does not retrieve information from certain processes.
However, he manages to recover the sha256
Could you please explain why this behavior and how to fix address this behavior ?
Path is Null
WmiPrvSE
- [(PID=5356) () Description=]
-- Path="None (SHA256=AD938C303F12EA8D164433CC7BA46FC7B9AE00F6F899E308D4317DAB46E25642)
-----
Get-FileHash : Impossible de lier l'argument au paramètre « Path », car il a la valeur Null.
Au caractère C:\Users\LEFBE\Desktop\Klic-20-12-2021\Process.ps1:4 : 33
+ $FileHash = (Get-FileHash -Path $_.Path -Algorithm SHA256 -ErrorActio ...
+ ~~~~~~~
+ CategoryInfo : InvalidData : (:) [Get-FileHash], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Get-FileHash
Question 2:
I'm having trouble retrieving the command line launched by the process. Could you please help me to get this information?
The code :
get-process | ForEach-Object {
$Name = $_.Name
$Desc = $_.Description
$FileHash = (Get-FileHash -Path $_.Path -Algorithm SHA256 -ErrorAction SilentlyContinue).hash
$ID = $_.ID
$Path = $_.Path
$CP = $_.Company
$CL = $_.Commandline
if ($Path -eq $null)
{
Write-Host "Path is Null"
$Path = "None"
Write-Host "$Name"
Write-Host "- [(PID=$ID) ($CP) Description=$Desc]"
Write-Host "-- Path=""$Path (SHA256=$FileHash)"
Write-Host $CL
Write-Host "-----"
}
else
{
Write-Host "$Name"
Write-Host "- [(PID=$ID) ($CP) Description=$Desc]"
Write-Host "-- Path=""$Path (SHA256=$FileHash)"
Write-Host $CL
Write-Host "-----"
}
}
Update 23/12/2021
The updated code works better than the first. (manage Null $Path value)
On the other hand, no command line can be obtained yet.
get-process | ForEach-Object {
$Name = $_.Name
$Desc = $_.Description
$ID = $_.ID
$Path = $_.Path
$CP = $_.Company
$CL = $_.Commandline
IF([string]::IsNullOrEmpty($Path)) {
$Path = "None"
$FileHash = "None"
write-Host "$Name"
Write-Host "- [(PID=$ID) ($CP) Description=$Desc]"
Write-Host "-- Path=""$Path (SHA256=$FileHash)"
Write-Host $CL
Write-Host "-----"
} else {
$FileHash = (Get-FileHash -LiteralPath $_.Path -Algorithm SHA256 -ErrorAction SilentlyContinue).hash
Write-Host "$Name"
Write-Host "- [(PID=$ID) ($CP) Description=$Desc]"
Write-Host "-- Path=""$Path (SHA256=$FileHash)"
Write-Host $CL
Write-Host "-----"
}
}
Thanks for your help,
LEFBE
You can use a calculated property with Select-Object to generate your new object. As for "having trouble retrieving the command line", I'm assuming you're unable to capture the output of your script with Out-File or similar, this is because Write-Host sends the output to the Information Stream and it's output can't be captured unless redirected (6>&1).
Get-Process | Select-Object Name, Description, #{
Name = 'Hash'
Expression = { (Get-FileHash $_.Path -Algorithm SHA256).Hash }
}, ID, Path, Company, CommandLine

how to use variable out of invoke-command in powershell?

I have below Invoke-command code, the script using hponcfg.exe file on remote server to get ILO configuration. few servers having issue with power capping and error returned by hponcfg.exe as
"Message = 0x0089 Power capping information is not available at this time, try again later."
My question is: I want to capture this error if generated by hponcfg inside invoke-command scriptblock and use it out of scriptblock.
$CurrentDir = (Split-Path $invocation.MyCommand.Path).ToLower()
$CurrentDir
$Credential = get-credential -message "Please supply SA account details."
$servers = gc .\servers.txt
#$Global:ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path
$date = (get-date).ToString("yyyyMMdd_HHmm")
$ILOContent = ".\ILOConfigData_$date.csv"
New-Item -path $ILOContent -type file -Force | out-null
Add-Content -Path $ILOContent -Value "ILO_Name,Model,ILOFIrmware,ILODevice,ILOFWDate,ILO_Domain,Network_Details,ILO_TimeZone,Directory_Users,LDAP_Directory_Authentication,Directory_Groups,SNMP_Settings,Directory_Server_Address"
Foreach($server in $servers){
if (Test-Connection -ComputerName $server -Quiet)
{
#$Frompath = ".\ILO_Prerequisite\"
#$To_Path = "C:\Program Files\Hewlett Packard Enterprise\HPONCFG"
$tmp="Drv_$server"
new-psdrive $tmp filesystem "\\$server\C$" -cred $cred|Out-Null
$Model = (Get-WmiObject -ComputerName $server -Class:Win32_ComputerSystem).model
Write-Host "Validating HPE pre-requisites on server:"$server -BackgroundColor DarkGray -ForegroundColor White
if (-not(test-path("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG")))
{
Write-Host "Corrupt 'HPONCFG' folder structure found. Remediating, will take few seconds." -ForegroundColor Red
New-Item -Path ("$($tmp):\Program Files\Hewlett Packard Enterprise\") -ItemType Directory -Name HPONCFG -Force|Out-Null
$To_Path =("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG")
$From_Path = ".\ILO-PreRequisite\*"
copy-item -path $From_Path -Destination $To_Path -recurse -Force
Sleep(6)
Write-Host "'HPONCFG' folder structure remediated." -ForegroundColor Green
}
Elseif (-not(test-path("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe")))
{
$To_Path =("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG")
Write-Host "Corrupt 'HPONCFG' folder structure found. Remediating, will take few seconds." -ForegroundColor Red
copy-item -path $From_Path -Destination $To_Path -recurse -Force
Sleep(6)
Write-Host "'HPONCFG' folder structure remediated" -ForegroundColor Green
}
remove-psdrive -name $tmp -force
#if (-not(test-path "C:\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe"))
# {
# do copy job
# write-host "Copying files and folders from $frompath to $topath" -ForegroundColor Yellow
# copy-item -path $frompath -Destination $topath -recurse
# }
$export = Invoke-Command -ComputerName $server -Credential $Credential -ScriptBlock {
New-Item -Path "C:\Program Files\Hewlett Packard Enterprise\HPONCFG" -ItemType File -Name Current_ILOConfig.xml -Force| Out-Null
Set-Location "C:\Program Files\Hewlett Packard Enterprise\HPONCFG"
$ILODataPath = Get-Location
$WantFile = "$ILODataPath\Current_ILOConfig.txt"
$FileExists = Test-Path $WantFile
If ($FileExists -eq $True) {Remove-Item $WantFile }
Sleep(2)
Write-Host "Gathering current ILO configuration for $ENV:COMPUTERNAME" -ForegroundColor Yellow
& "C:\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe" /a /w `
"C:\Program Files\Hewlett Packard Enterprise\HPONCFG\Current_ILOConfig.xml" |Out-Null
Get-Content .\Current_ILOConfig.xml
}
$export|Out-File "Current_ILOConfig.txt"
Sleep(3)
$ILORAW_DATA = Get-Content .\Current_ILOConfig.txt
$ILORAW_DATA|ForEach-Object{
$_ -replace '<!-- ' `
-replace ' -->' `
-replace '<' `
-replace ' />' `
-replace '"' `
}|Set-Content .\Current_ILOConfig.txt
$ILO_DATA = Get-Content .\Current_ILOConfig.txt
Write-Host "Getting ILO DNS details"
$DNS_NAME = $ILO_DATA |Where {$_ |Select-String -Pattern " DNS_NAME VALUE"," DOMAIN_NAME VALUE"}
$ILONAME = $DNS_NAME -split "="
$ILO_Name = $ILONAME[1]
$ILO_Domain = $ILONAME[3]
Write-Host "Getting ILO Network details"
$NT = $ILO_DATA | where {$_ |Select-String -Pattern " IP_ADDRESS VALUE"," SUBNET_MASK"," GATEWAY_IP_ADDRESS"," PRIM_DNS_SERVER VALUE", " SEC_DNS_SERVER VALUE"," TER_DNS_SERVER VALUE" }
$Network = [array]$NT -join "`n"
$Network_Details = $Network.Trim()
Write-Host "Getting ILO TimeZone"
$TZ= $ILO_DATA |Where {$_ | Select-String -Pattern " TIMEZONE VALUE"}
$TimeZone =$TZ -Split "="
$ILO_TimeZone = $TimeZone[1]
Write-Host "Getting ILO Directory Server Address" # Directory_Server_Address
$DSA = $ILO_DATA |Where {$_ | Select-String -Pattern " DIR_SERVER_ADDRESS"}
$DIR_SERVERADDRESS = $DSA -Split "="
$Directory_Server_Address = $DIR_SERVERADDRESS[1]
$ILODeviceID = #()
$ILODev = $ILO_DATA|where{$_|Select-String -Pattern "Device: "}
$ILODevStr = $ILODev -split(' ')
$ILODeviceID += $ILODevStr[1..2] -as [string]
$ILODeviceID += $ILODevStr[7]
$ILODeviceID += $ILODevStr[-1]
Write-Host "Getting LDAP Directory Authentication Enabled/Disabled?"
$LDAP_DIR = $ILO_DATA |Where {$_ | Select-String -Pattern " DIR_AUTHENTICATION_ENABLED"}
$LDAP_DIR_STATUS = $LDAP_DIR -split "="
$LDAP_Directory_Authentication = $LDAP_DIR_STATUS[1]
Write-Host "Getting ILO Device detail"
$ILOFIrmware = $ILODevStr[7]
Write-Host "Getting ILO Firmware Version"
$ILODevice = $ILODevStr[1,2]
Write-Host "Getting ILO Firmware Version date"
$ILOFWDate = $ILODevStr[-1]
Write-Host "Getting SNMP Settings" #SNMP_Settings
$SNMPADDRESS = $ILO_DATA |Where {$_ | Select-String -Pattern "SNMP_ADDRESS"}
$SNMP_DATA = #()
foreach($SNMP in $SNMPADDRESS)
{
$SNMP_DATA +=($SNMP -split "VALUE=")[1]
}
$SNMP_Settings = $SNMP_DATA -join "`n"
Write-Host "Getting ILO Directory User details"
$DIR_USER = $ILO_DATA |Where {$_ | Select-String -Pattern " DIR_USER_CONTEXT"}
$User =#()
foreach($Usr in $DIR_USER)
{
$User += ($Usr -split "VALUE=")[1]
}
#$User
$Directory_Users = $User -join "`n"
#group Account details
Write-Host "Getting ILO Directory Group details"
$DIR_GRPACCT = $ILO_DATA |Where {$_ | Select-String -pattern " DIR_GRPACCT"}
$ACCTs = #()
for($a=1;$a -le 10;$a++)
{
$GroupName = "DIR_GRPACCT" + $a + "_NAME"
#$Privilege = "DIR_GRPACCT" + $a + "_PRIV"
$DIR_GRPACCT = $ILO_DATA |Where {$_ | Select-String -pattern $groupname}
foreach ($acct in $DIR_GRPACCT)
{
$ACCTS += ($acct -split "VALUE=")[1]
}
$DIR_GRPACCTS = ($ACCTS -join "`n")
}
$data = "`"$ILO_Name`",`"$Model`",`"$ILOFIrmware`",`"$ILODevice`",`"$ILOFWDate`",`"$ILO_Domain`",`"$Network_Details`",`"$ILO_TimeZone`",`"$($Directory_Users.trimend())`",`"$LDAP_Directory_Authentication`",`"$($DIR_GRPACCTS.trimend())`",`"$($SNMP_Settings.trimend())`",`"$($Directory_Server_Address.trimend())`""
$Data |Out-File -Append $ILOContent
}
else
{
write-host -ForegroundColor Red "Server $server is not reachable"
$data = "`"$server`",`"not reachable`""
$Data |Out-File -Append $ILOContent
}
}
#Clear User defined variables
Write-Host "Performing Clean-up" -ForegroundColor Yellow
#Clear-Variable -Name ILO*
Function Get-ScriptVariable ($Name = '*')
{
# these variables may exist in certain environments (like ISE, or after use of foreach)
$special = 'ps','psise','psunsupportedconsoleapplications', 'foreach', 'profile'
$ps = [PowerShell]::Create()
$null = $ps.AddScript('$null=$host;Get-Variable')
$reserved = $ps.Invoke() |
Select-Object -ExpandProperty Name
$ps.Runspace.Close()
$ps.Dispose()
Get-Variable -Scope Global |
Where-Object Name -like $Name |
Where-Object { $reserved -notcontains $_.Name } |
Where-Object { $special -notcontains $_.Name } |
Where-Object Name
}Get-ScriptVariable|Out-Null
Get-ScriptVariable |Clear-Variable ;Write-Host "Clean-up completed." -ForegroundColor Green
Write-Host "Check detailed log stored at path: "$CurrentDir -ForegroundColor Green```
You can use try-catch-finally method to get your error messages.
Hi I have modified your script invoke-command part only. Please test and use it. This script is not tested.
$export = Invoke-Command -ComputerName $server -Credential $Credential -ScriptBlock {
try {
New-Item -Path "C:\Program Files\Hewlett Packard Enterprise\HPONCFG" -ItemType File -Name Current_ILOConfig.xml -Force | Out-Null
Set-Location "C:\Program Files\Hewlett Packard Enterprise\HPONCFG"
$ILODataPath = Get-Location
$WantFile = "$ILODataPath\Current_ILOConfig.txt"
$FileExists = Test-Path $WantFile
If ($FileExists -eq $True) { Remove-Item $WantFile }
Sleep(2)
Write-Host "Gathering current ILO configuration for $ENV:COMPUTERNAME" -ForegroundColor Yellow
& "C:\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe" /a /w `
"C:\Program Files\Hewlett Packard Enterprise\HPONCFG\Current_ILOConfig.xml" | Out-Null
Get-Content .\Current_ILOConfig.xml
}
catch {
return $_
}
}
$export | Out-File "Current_ILOConfig.txt"

Why is my if statement not being read properly?

I have a script that backs up a user profile from the local, or remote machine and places it onto a share: $Global:Shared_BackupPath = "\\server\share\". I've been tweaking it a little more and just ended up making some variables into Global variables (not sure if this is the issue - dont see why it would be).
This is the condition:
if(-not (Get-EventSubscriber)){
I tried changing it to -eq $null to see if it would make any difference, but it didn't.
Its just not analyzing the condition properly and goes on to display my message box before all Jobs are done: it's "supposed" to wait till there's no more events and then display the message box:
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
#Start-Sleep -Milliseconds 500
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
if(-not (Get-EventSubscriber)){
$Profile_Sum = Get-ChildItem -Path $Global:BackUp_Path -Recurse |
Measure-Object -Property length -Sum |
Select-Object -ExpandProperty Sum
$Size = try{if($Profile_Sum -lt 1048576){ $TinyByte = " {0:N2}" -f ($Profile_Sum / 1KB) + " KB"; $TinyByte }
elseif($Profile_Sum -gt 1048576 -and $Profile_Sum -lt 1073741824){ $MediumByte = " {0:N2}" -f ($Profile_Sum / 1MB) + " MB"; $MediumByte }
elseif($Profile_Sum -gt 1073741824){ $GiganticByte = " {0:N2}" -f ($Profile_Sum / 1GB) + " GB"; $GiganticByte } } Catch {}
$Begin_Time = Get-Item -Path $Global:BackUp_Path | Select-Object -ExpandProperty LastWriteTime
$End_Time = Get-Date -Format G
Get-Job | Remove-Job
[System.Windows.MessageBox]::Show("Copying Complete!`nStart Time: $Begin_Time `nEnd Time: $End_Time `nProfile Size copied: $Size")
}
} | Out-Null
}
I feel like I may have an idea due to the event itself being registered as a job but, not too sure how to go about it and have it wait until its done with ALL jobs before displaying the messagebox informing me when the copying is complete. Other than that, the script works just fine and anyone reading this can feel free to use it themselves. Heres the full Script:
Function PFL-UserBackUp{
[cmdletbinding()]
Param(
[Parameter(Mandatory=$false,
ValueFromPipeLine=$true,
ValueFromPipeLineByPropertyName=$true)]
[Alias('CN','Computer','server','node')]
[ValidateLength(1, 15)]
[String[]]$ComputerName = $env:COMPUTERNAME )
Begin{
$Global:Shared_BackupPath = "\\server\share\"
}
Process{
Foreach($Computer in $ComputerName){
Try{
$PSSession = New-PSSession -ComputerName $Computer -ErrorAction Stop
[array]$User_List = Invoke-Command -ScriptBlock {
Get-ChildItem -Path "C:\Users" -Exclude Public, Default* |
Sort-Object -Property LastWriteTime -Descending } -Session $PSSession
$userinfo1 = foreach ($user in $User_List.name) {
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) { "NO DISPLAY NAME in ADUC" }
elseif($LASTEXITCODE -eq 2) { "ACCOUNT NOT in ADUC" }
elseif($LASTEXITCODE -eq 0) { $userinfo }
else { "Error occured" }
}
$(for($i=0; $i -lt $User_List.Count; $i++){
[pscustomobject]#{
'User Display Name ' = "$($i): $($userinfo1[$i])"
' NAME ' = $User_List.name[$i]
'Last Modified' = "$($User_List.LastWriteTime[$i])"
'Profile Size ' = Try{
$ProfilePath = $User_List.FullName[$i]
$Profile_Sum = Invoke-Command -ScriptBlock {
Get-ChildItem -Path $Using:ProfilePath -Recurse |
Where-Object {$_.PSParentPath -match "Documents|Desktop|Music|Videos|Downloads|Links|Pictures|Favorites|Contacts" -and $_.DirectoryName -notmatch "OneDrive" } |
Measure-Object -Property length -Sum |
Select-Object -ExpandProperty Sum } -Session $PSSession
if($Profile_Sum -lt 1048576){ $TinyByte = " {0:N2}" -f ($Profile_Sum / 1KB) + " KB"; $TinyByte }
elseif($Profile_Sum -gt 1048576 -and $Profile_Sum -lt 1073741824){ $MediumByte = " {0:N2}" -f ($Profile_Sum / 1MB) + " MB"; $MediumByte }
elseif($Profile_Sum -gt 1073741824){ $GiganticByte = " {0:N2}" -f ($Profile_Sum / 1GB) + " GB"; $GiganticByte } #Profile Size
} Catch { "$($Error[0].Exception.Message.Split('.')[2].Trim())!" }
}
} ) | Out-Host
Write-Host "Press 'Q' to quit."
$ii = Read-Host -Prompt "Enter Number of Profile to Back-Up"
$i = $ii.Trim() -split ","
if([String]::IsNullOrEmpty($i) -eq $true) { "Null string"; Break }
elseif($i.ToLower() -like "q*") {"Q was selected. Stopping script."; Break }
<#
" "
" Following Profiles will be Saved:"
" ------------------------------------"
foreach($i in $index) { "$($i.trim()): $($userinfo1[$i])" }
" "
$Confirm = Read-Host -Prompt "Are you sure you want to continue? [Y/N]"
if($Confirm.ToLower().TrimStart() -like "n*" -or $Confirm.ToLower() -like "q*"){Break}
if([String]::IsNullOrEmpty($Confirm.Trim()) -eq $true) { "Null string"; Break }#>
$Profile_Path = "C:\Users\$($User_List.name[$i])"
$Literal_Name = $userinfo1[$i].Replace('/','-')
$Global:BackUp_Path = "$Global:Shared_BackupPath$Literal_Name"
$Test_Path = Test-Path -Path $Global:BackUp_Path
if($Test_Path -eq $false){
New-Item -Path $Global:BackUp_Path -ItemType Directory | Out-Null
Start-Process $Global:BackUp_Path}
elseif($Test_Path -eq $true){
$Find_OldName = Get-ChildItem -Path "$Global:Shared_BackupPath" -Filter "$Literal_Name" -Directory |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -ExpandProperty BaseName -First 1
$New_PathName = $Find_OldName + "1"
New-Item -Path "$Global:Shared_BackupPath" -Name $New_PathName -ItemType Directory -OutVariable Global:BackUp_Path | Out-Null #Global:BackUp_Path variable declared
$Global:BackUp_Path = $Global:BackUp_Path.FullName
Start-Process $Global:BackUp_Path}
$Global:Start_Time = Get-Date -Format G
#Favorites Copy
$FireFox_Favorites = "C:\Users\$($User_List.name[$i])\AppData\Roaming\Mozilla\Firefox\Profiles\*.default\places.sqlite"
$Chrome_Favorites = "C:\Users\$($User_List.name[$i])\AppData\Local\Google\Chrome\User Data\Default\Bookmarks"
$Chrome_Favorites2 = "C:\Users\$($User_List.name[$i])\AppData\Local\Google\Chrome\User Data\Default\Bookmarks.bak"
$Sticky_Notes = "C:\Users\$($User_List.name[$i])\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState\plum.sqlite"
$Favorites_Array = #($FireFox_Favorites,$Chrome_Favorites,$Chrome_Favorites2,$Sticky_Notes)
Foreach($File in $Favorites_Array){
$Test_File = Invoke-Command -ScriptBlock { Test-Path -Path $File }
if($Test_File -eq $true){
Copy-Item -Path $File -Destination $Global:BackUp_Path -Force -Recurse -FromSession $PSSession
}
}
#Folders Copy
$Folders = #('Desktop','Documents','Favorites','Links','Downloads','Music','Videos','Pictures','Contacts')
Foreach($Folder in $Folders){
#Create Arugments for seperate thread
$ArgumentsArray = $null
$ArgumentsArray = #()
$ArgumentsArray += "\\$Computer\c$\Users\$($User_List.name[$i])\$Folder"
$ArgumentsArray += $Global:BackUp_Path
$job = Start-Job -ScriptBlock { Copy-Item -Path $args[0] -Destination $args[1] -Force -Recurse } -Name $Folder -ArgumentList $ArgumentsArray
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
#Start-Sleep -Milliseconds 500
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
if(-not (Get-EventSubscriber)){
$Profile_Sum = Get-ChildItem -Path $Global:BackUp_Path -Recurse |
Measure-Object -Property length -Sum |
Select-Object -ExpandProperty Sum
$Size = try{if($Profile_Sum -lt 1048576){ $TinyByte = " {0:N2}" -f ($Profile_Sum / 1KB) + " KB"; $TinyByte }
elseif($Profile_Sum -gt 1048576 -and $Profile_Sum -lt 1073741824){ $MediumByte = " {0:N2}" -f ($Profile_Sum / 1MB) + " MB"; $MediumByte }
elseif($Profile_Sum -gt 1073741824){ $GiganticByte = " {0:N2}" -f ($Profile_Sum / 1GB) + " GB"; $GiganticByte } } Catch {}
$Begin_Time = Get-Item -Path $Global:BackUp_Path | Select-Object -ExpandProperty LastWriteTime
$End_Time = Get-Date -Format G
Get-Job | Remove-Job
[System.Windows.MessageBox]::Show("Copying Complete!`nStart Time: $Begin_Time `nEnd Time: $End_Time `nProfile Size copied: $Size")
}
} | Out-Null
}
" "
Write-Output -InputObject "Copying will be done in background."
Write-Output -InputObject "You will be notified when copying is done."
} catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
"Unable to connect to PC: $Computer `nError: $($Error[0].Exception.Message.Split('.')[2].Trim())!"
}
}
}
}
I removed some information that could get me in trouble but, it's all cosmetics.(:
EDIT: I must be on crack but, everything is working now. Only changes I made was clearing the global variables ($Global:var = $null) before assigning it a value. Thank you all for the suggestions. Another change i made was change Copy-Item to Robocopy instead.
To just answer your question:
Why is my if statement not being read properly?
Just before you evaluate Get-EventSubscriber your are cancelling your event subscription and thus deleting your event subscriber. Get-EventSubscriber therefore returns $null which evaluates to $true, when negated. In conclusion, the code after your if statement will always be executed immediately.
Commented code:
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
$eventSubscriber | Unregister-Event # Here you cancel your event subscription
$eventSubscriber.Action | Remove-Job
if (-not (Get-EventSubscriber)) { # Therefore, Get-EventSubscriber returns $null; not $null evaluates to $true
...
The relevant part in the documentation of Unregister-Event:
The Unregister-Event cmdlet cancels an event subscription that was created by using the Register-EngineEvent, Register-ObjectEvent, or Register-WmiEvent cmdlet.
When an event subscription is canceled, the event subscriber is deleted from the session and the subscribed events are no longer added to the event queue. When you cancel a subscription to an event created by using the New-Event cmdlet, the new event is also deleted from the session.

Copy document library to document library sharepoint online with powershell

I am making a PowerShell script to copy content from a document library to a different document library. So far I have the following code
{
# Define final variables
$SourceUrlComplete = $SourceUrl + $SourceSite + "/" + $SourceSubSite
$DestinationUrlComplete = $SourceUrl + "Contracts"
# Set connections
Write-host "Start copy process..." -f Yellow
Write-host "1. Connect to $sourceUrlComplete" -f Yellow
$SourceConnection = Connect-PnPOnline -Url $SourceUrlComplete -ClientId $ClientId -ClientSecret $ClientSecret -WarningAction Ignore -ReturnConnection
Write-host " Connected" -f DarkGreen
Write-host "2. Connect to $TargetUrlComplete" -f Yellow
$DestinationConnection = Connect-PnPOnline -Url $DestinationUrlComplete -ClientId $ClientId -ClientSecret $ClientSecret -WarningAction Ignore -ReturnConnection
Write-host " Connected" -f DarkGreen
$SourceList = Get-PnPList -Identity $SourceLibrary -Includes RootFolder -Connection $SourceConnection
$SourceListUrl = $SourceList.RootFolder.ServerRelativeUrl
$DestinationList = Get-PnPList -Identity $DesitinationLibrary -Includes RootFolder -Connection $DestinationConnection
$DestinationListUrl = $DestinationList.RootFolder.ServerRelativeUrl
}
This works, I have connections, I have the list too. I can also use Get-PnpListItem and will get all list items. What I'm now left with is the following:
I need to look through the items and based on a custom column check a folder exists on the target
Copy the file to the target
Unfortunately, the column 'title' and 'name' are not always populated in the source item
Note: the lists are on two different sites. But if the solution is to create a temp list on-site A then copy that to site B please let me know that too.
Can someone advise on the next step? I get stuck with either coping one on one of the whole list or messages saying to use spFileCollection.add().
So what I've done now is make this function
Function ProcessFiles {
$SourceUrlComplete = $SourceUrl + $Site + "/" + $SubSite
$DestinationUrlComplete = $SourceUrl + "Contracts"
Write-host "Start copy process..." -f Yellow
Write-host " 1. Connect to $sourceUrlComplete" -f Yellow
$SourceConnection = Connect-PnPOnline -Url $SourceUrlComplete -ClientId $ClientId -ClientSecret $ClientSecret -WarningAction Ignore -ReturnConnection
Write-host " Connected" -f DarkGreen
Write-host " 2. Connect to $DestinationUrlComplete" -f Yellow
$DestinationConnection = Connect-PnPOnline -Url $DestinationUrlComplete -ClientId $ClientId -ClientSecret $ClientSecret -WarningAction Ignore -ReturnConnection
Write-host " Connected" -f DarkGreen
Write-host " 3. Process files" -f Yellow
$SourceFiles = Get-PnPFolderItem -Connection $SourceConnection -FolderSiteRelativeUrl $SourceList -ItemType File
$SourceListItems = Get-PnPListItem -List $SourceList -Connection $SourceConnection
foreach ($SourceFile in $SourceFiles) {
$process = "yes"
foreach ($SourceListItem in $SourceListItems)
{
if ($SourceListItem["FileRef"] -eq $SourceFile.ServerRelativeUrl -and $process -eq "yes")
{
$process = "no"
Write-host " - $($SourceFile.ServerRelativeUrl)" -f DarkYellow
Get-PnPFile -Url $SourceFile.ServerRelativeUrl -Path $ProcessFolder -FileName $SourceFile.Name -AsFile -Connection $SourceConnection -Force
$SourcePath = $ProcessFolder + "\" + $SourceFile.Name
$DestinationFolder = $SourceListItem["CustomerName"]
$DestinationItemValues = #{
"CustomerName" = $SourceListItem["CustomerName"]
"Title" = $SourceListItem["Title"]
"CustomerNo" = $SourceListItem["CustomerNo"]
"DocType" = $SourceListItem["DocType"]
"DocDate" = $SourceListItem["DocDate"]
"DocCode" = $SourceListItem["DocCode"]
"Modified" = $SourceListItem["Modified"]
"Created" = $SourceListItem["Created"]
"Visibility" = $SourceListItem["Visibility"]
"CompanyID" = $SourceListItem["CompanyID"]
}
$DestinationFolder = "Contracts"
if ($SourceSubSite -eq "BE")
{
$DestinationFolder = $DestinationFolder + "\SOME_FOLDER\" + $SourceListItem["CustomerName"]
Add-PnPFile -Path $SourcePath -Connection $DestinationConnection -Folder "$DestinationFolder" -Values $DestinationItemValues | Out-Null
Remove-Item $SourcePath -Recurse
Write-host " - DONE" -f DarkGreen
}
else
{
Write-host " - FAILED" -f Red
}
}
}
}
Write-host " Done" -f DarkGreen
}
Right now it works, but I download the file temporarily. I need to add something to replace special characters where the new folder is determined. I'm not sure this is the best way currently.