I have a question regarding sample code. I am running some scripts in O365, "Running script" as below. I want to do when a PSSession enters a "Broken" state, it will pause the script, and remove broken session (Remove-PSSession ) and re-connecting PSSession (following "Re-connecting code" as below), then restart the script. I tried to write this but but I am no familiar with coding.... Can anyone help?.....
(Server 2008 R2 SP1/PowerShell)
Any help would be appriciated.
Running Script-----
Import-Csv D:\work\users.csv | ForEach {
Grant-CsConferencingPolicy $_.UserPrincipalName -PolicyName BposSAllModalityNoFT}
Import-Csv D:\work\users.csv | ForEach {
Grant-CsExternalAccessPolicy $_.UserPrincipalName -PolicyName FederationOnly}
Re-connecting code-------
$sfboSession = New-CsOnlineSession -Credential $credential
Import-Pssession $sfboSession -AllowClobber
`Import-csv D:\IDMaster\Tools\SkypeTool\users.txt | foreach {
Do {
Grant-CsConferencingPolicy $_.UserPrincipalName -PolicyName BposSAllModalityNoFT
if ($? -ne "True")
{
get-pssession | remove-pssession
$sfboSession = New-CsOnlineSession -credential $credential
Import-PSSession $sfboSession -AllowClobber }
} # End of 'Do'
Until ($? -eq "True")
Write-Host $_.UserPrincipalName "BposSAllModalityNoFT"
Do {
Grant-CsExternalAccessPolicy $_.UserPrincipalName -PolicyName FederationAndPICDefault
if ($? -ne "True")
{
get-pssession | remove-pssession
$sfboSession = New-CsOnlineSession -credential $credential
Import-PSSession $sfboSession -AllowClobber }
} # End of 'Do'
Until ($? -eq "True")
Write-Host $_.UserPrincipalName "FederationAndPICDefault"
$string = $_.UserPrincipalName + " " + "BposSAllModalityNoFT" + " " + "FederationAndPICDefault"
Write-Output $string | Out-file D:\IDMaster\Tools\SkypeTool\Modify_Log.csv -Append -Encoding default
}`
Related
I wish to run the below PowerShell script as a scheduled task to pull provisioning logs from Azure AD. However, I do not wish to embed the password. I appreciate this is not a problem specific to PowerShell or Microsoft Online. What technique can I use to not have the password stored as clear text? Thanks
Script credits go to: Pawel Janowicz
$AzureUsername = 'log.reader#tenant.net'
$Password = "xxxxxx"
$SecureString = ConvertTo-SecureString -AsPlainText $Password -Force
$SecuredCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AzureUsername,$SecureString
$OutputCSV = "$Env:USERPROFILE\desktop\DirSyncProvisioningErrors_$(Get-Date -Format "yyyyMMdd").csv"
###### Connecting ############################################################################################################
Try{
[void] (Connect-MsolService -Credential $SecuredCreds)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $SecuredCreds -Authentication Basic -AllowRedirection
[void] (Import-PSSession $Session -DisableNameChecking)
}
Catch{
$_.Exception.Message
Read-Host 'Press enter to close the window'
Remove-PSSession $Session
Exit
}
###### Getting errors ########################################################################################################
If(Get-MsolHasObjectsWithDirSyncProvisioningErrors){
Try{
$Errors = Get-MsolDirSyncProvisioningError -All | select DisplayName,ObjectID,ObjectType,ProvisioningErrors
$Results = Foreach ($i in $Errors){
$AllErrors = $i.ProvisioningErrors
$AllErrors | %{
$ErrorItem = $_
Get-AzureADObjectByObjectId -ObjectIds $i.objectid | Foreach{
New-Object PSObject -Property ([ordered]#{
'Displayname' = $i.displayname
'ObjectType' = $i.ObjectType
'Attribute' = $ErrorItem.propertyname
'Conflicting value' = $ErrorItem.propertyvalue
})
}
}
}
}
Catch{
$_.Exception.Message
Read-Host 'Press enter to close the window'
Remove-PSSession $Session
Exit
}
}
###### Results ###############################################################################################################
If($Results){
$Results | Format-Table -AutoSize
#Exporting CSV
$Results | Export-CSV $OutputCSV -NoTypeInformation -Force
}
Remove-PSSession $Session
Thank You Theo for providing your suggestion as a comment. Making this as answer to help other community member.
I have executed the command and getting a display to enter the password rather than it was manually provided in script itself.
$SecuredCreds = Get-Credential -UserName 'log.reader#tenant.net' -Message "Please enter credentials"
$OutputCSV = "$Env:USERPROFILE\desktop\DirSyncProvisioningErrors_$(Get-Date -Format "yyyyMMdd").csv"
###### Connecting ############################################################################################################
Try{
[void] (Connect-MsolService -Credential $SecuredCreds)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $SecuredCreds -Authentication Basic -AllowRedirection
[void] (Import-PSSession $Session -DisableNameChecking)
}
Catch{
$_.Exception.Message
Read-Host 'Press enter to close the window'
Remove-PSSession $Session
Exit
}
###### Getting errors ########################################################################################################
If(Get-MsolHasObjectsWithDirSyncProvisioningErrors){
Try{
$Errors = Get-MsolDirSyncProvisioningError -All | select DisplayName,ObjectID,ObjectType,ProvisioningErrors
$Results = Foreach ($i in $Errors){
$AllErrors = $i.ProvisioningErrors
$AllErrors | %{
$ErrorItem = $_
Get-AzureADObjectByObjectId -ObjectIds $i.objectid | Foreach{
New-Object PSObject -Property ([ordered]#{
'Displayname' = $i.displayname
'ObjectType' = $i.ObjectType
'Attribute' = $ErrorItem.propertyname
'Conflicting value' = $ErrorItem.propertyvalue
})
}
}
}
}
Catch{
$_.Exception.Message
Read-Host 'Press enter to close the window'
Remove-PSSession $Session
Exit
}
}
###### Results ###############################################################################################################
If($Results){
$Results | Format-Table -AutoSize
#Exporting CSV
$Results | Export-CSV $OutputCSV -NoTypeInformation -Force
}
Remove-PSSession $Session
Hello I have been trying to make this script work for some time now, but I keep running into problems. The script is written with multiple servers in mind, although I am just testing it only on one test system for now.
Following I will post the script.
#List of Servers
$SQLServer = #('testserver.net')
$ApplicationServer = #('testserver.net')
$Servers = #($SQLServer, $ApplicationServer)
$ServiceName = #('tomcat9', 'MSSQLSERVER')
#Information Message
Write-Host "Starting update process for the following Servers:" $Servers "and Services:" $ServiceName
#Gets status of Servers
ForEach ($Index in $Servers)
{
Invoke-command {Get-Service tomcat9} -comp $Servers[$Index]
Invoke-command {Get-Service -Name 'MSSQLSERVER'} -comp $Servers[$Index]
}
#Information Message
Write-Host "Stopping the specified Services:" $ServiceName
#Stops services
#Sequentially stops TomCat and then DB Applications
ForEach ($Index in $Servers)
{
$ArrayService = Invoke-Command {Get-Service tomcat9} -comp $Servers[$Index]
if ($ArrayService.Status -ne "Stopped")
{
Invoke-Command {Stop-Service tomcat9} -comp $Servers[$Index]
}
$ArrayService = Invoke-Command {Get-Service -Name 'MSSQLSERVER'} -comp $Servers[$Index]
if ($ArrayService.Status -ne "Stopped")
{
Invoke-Command {Stop-Service -Name 'MSSQLSERVER'} -comp $Servers[$Index]
}
}
#Information Message
Write-Host "Will now start Windows Updates on servers and reboot"
#Will Update Windows, automatically reboot and out the log in the specified directory. This will be done to all listed Servers
ForEach ($Index in $Servers)
{
$Scriptblock = {
Invoke-WUJob -Comp $Servers[$Index] -RunNow -Confirm:$false -Verbose -Script {
Install-WindowsUpdate -MicrosoftUpdate -NotCategory "SilverLight" -NotTitle "Preview" -AcceptAll -AutoReboot | Out-File C:\PSWindowsUpdate.log
}
}
Invoke-Command -Comp $Servers[$Index] -ScriptBlock $Scriptblock
}
#Information Message
Write-Host "Starting up Services again"
#Starting SQL Server and checking if its running, if not running it will give more time before the Script continues
ForEach ($Index in $SQLServer)
{
$ArrayService = Invoke-Command {Get-Service -Name $ServiceName} -comp $SQLServer[$Index]
$FilteredService = $ArrayService | where {$_ -like 'MSQL'}
while ($FilteredService.Status -ne 'Running')
{
Invoke-Command {Start-Service $FilteredService} -comp $SQLServer[$Index]
Write-Host $FilteredService.Status
Write-Host "SQL Service starting on " $SQLServer[$Index]
function Check-Status
{
Start-Sleep -seconds 30
$FilteredService.Refresh()
if ($FilteredService.Status -eq 'Running')
{
Write-Host "SQL Service running"
#Invoke-Command {Start-Service $ArrayService | where {$_ -like 'tomcat9'}} -comp $ApplicationServer
}
else
{
Check-Status
}
}
}
}
#Starting TomCat Service again
ForEach ($Index in $ApplicationServer)
{
Write-Host "MUMService starting on " $ApplicationServer[$Index]
#Invoke-Command {Start-Service $ArrayService | where {$_ -like 'tomcat9'}} -comp $ApplicationServer[$Index]
$ServiceStatus = Invoke-Command {Get-Service tomcat9} -comp $ApplicationServer[$Index]
if ($ServiceStatus.Status -eq 'Running')
{
Invoke-Command {Start-Service $ArrayService | where {$_ -like 'tomcat9'}} -comp $ApplicationServer[$Index]
Write-Host "MUM Service running"
}
else
{
Invoke-Command {Start-Service $ArrayService | where {$_ -like 'tomcat9'}} -comp $ApplicationServer[$Index]
}
}
ForEach ($Index in $Servers)
{
invoke-command {Get-Service mum_software_tomcat9} -comp $Servers[$Index]
invoke-command {Get-Service -Name 'MSSQLSERVER'} -comp $Servers[$Index]
}
Either my logic is really wrong, or this doesnt work this way in powershell, but when I try to execute the script as is, there is an error for the parameter 'ComputerName'. It says that the argument is null or empty. Provide an argument that is not null or empty and then try the command again. Apparently it does not like $SQLServer[$Index].
The update functionality itself seems to work by itself though.
What is wrong with this?
So my issue is that this script will run fine the first time but if I try running it again, the PSSessions are still active despite the
Get-PSSession | Remove-PSSession
lines. I've tried other methods like calling the computernames or instanceIDs but still won't close them. I'm not sure why the sessions aren't closing but it's the last thing that is keeping this script from working correctly.
Also this is made from the Microsoft article here: https://support.microsoft.com/en-us/help/2956029/migrationpermanentexception-cannot-find-a-recipient-that-has-mailbox-g
#Exchange session for EOL
function EOLExchange-Session {
Write-Host "Importing Exchange Scripting Module.....please wait a few seconds"
Write-Host "NOTE: Login with your username#aklsj.com credentials for Office 365" -ForegroundColor red -BackgroundColor white
pause
$counter = 0
while ($counter -lt 3) {
try {
$EOLPSSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell-liveid?DelegatedOrg=yalldontneedtoknow.com -Authentication Basic -AllowRedirection -Credential $UserCredential -ea stop
write-host "success"
$counter = 10
}
catch {
write-host "failed"
$counter++
if ($counter -ge 3) {
print "Too many attempts"
exit
}
}
}
Import-PSSession $EOLPSSession -AllowClobber -DisableNameChecking -CommandName Get-Mailbox, Set-Mailbox
$SessionID = $EOLPSSession.InstanceId
Write-Host "-------------Instance ID = " $PSSession.InstanceId
Write-Host "-------------Exchange-Session ID = " $SessionID
$SessionID
}
#Exchange session for On-Prem
function OPExchange-Session {
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction Stop
#Write-Host "Importing Exchange Scripting Module.....please wait a few seconds"
#Connect to Exchange using Remote Shell <-- allows Exchange commands in this script
$OPPSSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://mindyabusiness.com/PowerShell/ -Authentication Kerberos -AllowRedirection
Import-PSSession $OPPSSession -AllowClobber -DisableNameChecking -CommandName Get-RemoteMailbox, Set-RemoteMailbox
$SessionID = $OPPSSession.InstanceId
#Write-Host "-------------Instance ID = "$PSSession.InstanceId
#Write-Host "-------------Exchange-Session ID = "$SessionID
$SessionID
}
Function End-Script($SessionID, $f_runtype) {
Write-Host "Log File: $LogFile"
Write-Host ""
if ($SessionID -ne $null) {
$s = Get-PSSession -InstanceId $SessionID
Remove-PSSession -Session $s
}
if((Get-Content $LogFile) -eq $Null) {
Remove-Item $LogFile
} else {
#Set Log File to Read Only
Set-ItemProperty -Path $LogFile -Name IsReadOnly -Value $true
}
Write-Host "Script Complete" -ForegroundColor Gray
Read-Host "Press enter to close the script"
exit
}
Function SyncADConnect {
$s = New-PSSession -computerName server
Invoke-Command -Session $s -Scriptblock {Start-ADSyncSyncCycle -PolicyType Delta}
Remove-PSSession $s
End-Script
}
#Removes any PSSessions before running
Get-PSSession | Remove-PSSession
#Find current path script is executing from
$ScriptPath = $PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
$ScriptPath = $ScriptPath + "\"
#Setup Log File
$LogPath = $ScriptPath + "Logs\"
$LogFilename = "SetExchangeGUID_$((Get-Date).ToString('yyyy-MM-dd_hh-mm-ss')).log"
$LogFile = $LogPath + $LogFilename
New-Item -Path "$LogFile" -ItemType File
Write-Host "Checking Domain Admin Permissions...."
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($CurrentUser)
#Make sure user is a domain admin
if(!($WindowsPrincipal.IsInRole("Domain Admins")))
{
Write-Host "You must be logged in as a Domain Admin to run this script" -ForegroundColor Red
End-Script
} else {
Write-Host "Domain Admin permissions detected, please wait....."
}
$today = Get-Date -Format yyyy-MM-dd_hh-mm-ss
$msg = "Run on " + $today + ". Run by " + $env:username
$msg | out-file $LogFile -Append
#Clear-Host
$CloudMailbox = Read-Host "Enter the identity of the cloud mailbox"
Write-Host "Connecting to EOL"
EOLExchange-Session
$SessionID = $EOLPSSession.InstanceId
Write-Host $SessionID
#Fetches EOL ExchangeGUID and trims to just the GUID
$TempCloudGUID = Get-Mailbox $CloudMailbox | Format-List ExchangeGUID | Out-String
$CloudGUID = $TempOnPremGUID.Substring(19).Trim()
#Clear-Host
Write-Host "The EOL GUID is $CloudGUID"
pause
Write-Host "Connecting to On-Prem"
OPExchange-Session
#Fetches ExchangeGUID and trims to just the GUID
$TempOnPremGUID = Get-RemoteMailbox $CloudMailbox | Format-List ExchangeGUID | Out-String
$OnPremGUID = $TempOnPremGUID.Substring(19).Trim()
#Checks if GUID is all zeros
#$ZeroGUID = "00000000-0000-0000-0000-000000000000"
#if ($OnPremGUID -eq $ZeroGUID) {
#Write-Host "The value isn't stamped on the on-premises remote mailbox. Ending script"
#End-Script
#} else {
#Write-Host $CloudMailbox "On-prem GUID is" $OnPremGUID
#}
#Clear-Host
Write-Host "EOL GUID is $CloudGUID"
Write-Host "On-prem GUID is $OnPremGUID"
if ($CloudGUID -eq $OnPremGUID) {
Write-Host "Exchange GUIDs already match, ending script."
End-Script
} else {
$confirmation = Read-Host "The GUIDs are different, would you like to set the EOL GUID to be the same as On-Prem?"
if ($confirmation -eq 'y') {
Set-RemoteMailbox $CloudMailbox -ExchangeGUID $CloudGUID
$msg = "$CloudMailbox has been changed to use $CloudGUID in EOL and On-Prem"
$msg | out-file $LogFile -Append
Write-Host "GUID for $CloudMailbox has been set. Syncing ADSyncClcye and ending script"
Get-PSSession | Remove-PSSession
SyncADConnect
}
else {End-Script}
}
No reason to do this from scratch. There are already tools/addons to do this for you.
See these:
Connect to all Office 365 Services PowerShell (Supports MFA too)
Using our All-in-One PowerShell script, you can connect to all Office
365 Services using a single cmdlet. It supports both MFA and non-MFA
account -Exchange Online -Azure AD -SharePoint Online -Skype for
Business Online -Security & Compliance Center -Teams
https://gallery.technet.microsoft.com/PowerShell-Script-to-4081ec0f/file/225256/1/ConnectO365Services.ps1
https://blog.rmilne.ca/2015/02/02/using-exchange-powershell-remoting-with-integrated-scripting-environmentise
https://jaapwesselius.com/2013/07/21/ise-remote-powershell-and-exchange-2013
Adding Exchange Shell items to PowerShell ISE
# in the Microsoft.PowerShellISE_profile.ps1 file, add the following contents:
$psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add(
"Connect to Exchange # Contoso", {
$ExSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'http://exserver.contoso.com/PowerShell/' -Authentication Kerberos
Import-PSSession $ExSession
},
"Control+Alt+1"
)
$psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add(
"Connect to Exchange On-Premise", {
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
. $env:ExchangeInstallPath\bin\RemoteExchange.ps1
Connect-ExchangeServer –auto
},
"Control+Alt+2"
)
$psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add(
"Connect to Exchange Online", {
$o365Cred = Get-Credential
$o365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'https://ps.outlook.com/powershell/' -Credential $o365Cred -Authentication Basic -AllowRedirection
Import-PSSession $o365Session
},
"Control+Alt+3"
)
As for this...
Get-PSSession | Remove-PSSession
... though it should work, I've often had this be a bit quirky, with forcing a loop.
Get-PSSession | ForEach {Remove-PSSession -Id $PSItem.Id}
I am still researching the best way to do this. If anyone has a suggestion please let me know.
I am looking to pass PowerShell commands to a remote machine and receive verification that the command was successful.
The script should not proceed until result is received.
If command fails it should attempt again until it is successful on the remote computer, failure may occur if AD and Skype replication has not completed.
Here is what I have so far.
Not quite working but the above 3 rules. If there is a better way of doing this I am all ears.
$SkypeFeRemoteComputers = Get-SkypeRegistrarPoolInfo -Pool $RegistrarPool
$RemoteFEComputerCompletedSuccessfull = $false
foreach ($Computer in $SkypeFeRemoteComputers) {
if ($RemoteFEComputerCompletedSuccessfull -eq $false) {
try {
Invoke-Command -ComputerName $Computer -AsJob -JobName myJob_NewCommonAreaPhone -ErrorAction Stop -ArgumentList $LineURI,$RegistrarPool, $OU_CommonArea, $Description, $DisplayName, $DisplayNumber, $SIP -ScriptBlock {
Param($R_LineURI, $R_RegistrarPool, $R_OU_CommonArea, $R_Description, $R_DisplayName, $R_DisplayNumber, $R_SIP)
New-CsCommonAreaPhone -LineUri $R_LineURI -RegistrarPool $R_RegistrarPool -OU $R_OU_CommonArea -Description $R_Description -DisplayName $R_DisplayName -DisplayNumber $R_DisplayNumber -SipAddress $R_SIP -WhatIf;
Move-CsCommonAreaPhone -Identity $R_SIP -Target $R_RegistrarPool;
Grant-CsClientPolicy -PolicyName "SkypeUI" -Identity $R_SIP;
Grant-CsVoicePolicy -PolicyName "NA-TX-LAP" -Identity $R_SIP;
Grant-CsDialPlan -PolicyName "NA-TX-LAP" -Identity $R_SIP;
Set-CsClientPin -Identity $R_SIP -Pin 1111;
}
Get-Job
$Result = Invoke-Command -Session $Session -ScriptBlock {
Receive-Job -Name myJob_NewCommonAreaPhone -Keep
}
if ($Result -eq $true) {
$RemoteFEComputerCompletedSuccessfull = $true
}
} catch {
Add-Content Unavailable-Computers.txt $Computer
}
}
}
Write-Host "New-CsCommonAreaPhone -LineUri $lineuri -RegistrarPool $SFBFQDNRegistrarPool -OU $OU -Description $Description -DisplayName $DisplayName -DisplayNumber $DisplayNumber -SipAddress $SIP"
} else {
Write-Host "Set-CsCommonAreaPhone -identity $sip -sipaddress $sip -DisplayName $phone.Display -DisplayNumber $phone.Display"
}
}
Somethings I am researching to do this is perhaps also Invoke-Expression.
I have not yet found a solution to validate the script sent ran successfully or not. However the next best item I could come up with was to test that WinRM I could communicate and would accept commands. Then I guess I have to just trust WinRM completed the Invoke Command.
Function Enable-CommonAreaPhones
{
[CmdletBinding()]
param
(
#[Parameter(Position = 2)]
[Parameter(Mandatory)]
$DisplayName,
[Parameter(Mandatory)]
$SIP,
[Parameter(Mandatory)]
$LineURI,
[Parameter(Mandatory)]
$OU_CommonArea,
[Parameter(Mandatory)]
$CreateNewCAP = $true,
[Parameter(Mandatory)]
$RegistrarPool,
[Parameter(Mandatory)]
$DisplayNumber,
[Parameter(Mandatory)]
$Description
)
<#
dynamicparam {
#https://mcpmag.com/articles/2016/10/06/implement-dynamic-parameters.aspx
#https://stackoverflow.com/questions/42318419/powershell-using-dynamic-parameters-value
#https://github.com/PowerShell/PowerShell/issues/3704
$ParameterName_SFBRegistrarPool = 'SFBRegistrarPool'
$ParamAttrib = New-Object System.Management.Automation.ParameterAttribute
$ParamAttrib.Mandatory = $true
$ParamAttrib.ParameterSetName = '__AllParameterSets'
$AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$AttribColl.Add($ParamAttrib)
$ValidateItems = (get-csservice -Registrar).PoolFqdn
$AttribColl.Add((New-Object System.Management.Automation.ValidateSetAttribute($ValidateItems)))
$RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName_SFBRegistrarPool, [string], $AttribColl)
$RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$RuntimeParamDic.Add($ParameterName_SFBRegistrarPool, $RuntimeParam)
return $RuntimeParamDic
}
begin
{$RegistrarPool = $PsBoundParameters[$ParameterName_SFBRegistrarPool]}
process
{}
End
{}
#>
if ($CreateNewCAP)
{
<#
#$Description = "Huddle-N405-172B"
#$DisplayName = "(713)577-3160"
#$DisplayNumber = "+1-713-577-3160"
#$LineURI = 'tel:+17135773160;ext=3160'
#$SIP = 'sip:Huddle-N405-172B.BR172B#mrcglobal.com'
#$OU = "OU=172B LA PORTE -- TX,OU=Gulf Coast,OU=CAP,OU=Lync,DC=mcjunkinredman,DC=com"
#$RegistrarPool = 'hexlsfepool.mcjunkinredman.com'
#>
param($LineURI,$RegistrarPool, $OU_CommonArea, $Description, $DisplayName, $DisplayNumber,$SIP )
write-host "New-CsCommonAreaPhone -LineUri $lineuri -RegistrarPool $SFBFQDNRegistrarPool -OU $OU -Description $Description -DisplayName $DisplayName -DisplayNumber $DisplayNumber -SipAddress $SIP"
New-CsCommonAreaPhone -LineUri $LineURI -RegistrarPool $RegistrarPool -OU $OU_CommonArea -Description $Description -DisplayName $DisplayName -DisplayNumber $DisplayNumber -SipAddress $SIP -WhatIf;
Grant-CsClientPolicy -PolicyName "SkypeUI" -Identity $SIP;
Grant-CsVoicePolicy -PolicyName "NA-TX-LAP" -Identity $SIP;
Grant-CsDialPlan -PolicyName "NA-TX-LAP" -Identity $SIP;
#Set-CsClientPin –Identity $SIP -Pin 1111;
#Move-CsCommonAreaPhone -Identity $SIP -Target $R_RegistrarPool;
}
Else
{
#Get-CsCommonAreaPhone | Set-CsCommonAreaPhone -Enabled $True
#Get-CsCommonAreaPhone -Filter {Description -eq $Null} | Set-CsCommonAreaPhone -Description "Common area phone"
#Get-CsCommonAreaPhone -Filter {LineUri -eq "tel:+14255556710"} | Set-CsCommonAreaPhone -DisplayName "Employee Lounge"
}
}
function invoke-SkypeObject_RemoteModification_CommonAreaPhones
{
#Finds all Front End Servers
$SkypeFeRemoteComputers = Get-SkypeRegistrarPoolInfo -Pool $RegistrarPool
$RemoteFEComputerCompletedSuccessfull = $false
ForEach ($Computer in $SkypeFeRemoteComputers)
{
#Validates Command has only ran on 1 machine
#Validates the computer exists and can accept invoke commands via the WinRM Command
If ((!($RemoteFEComputerCompletedSuccessfull)) -and (Test-Connection -ComputerName $env:COMPUTERNAME -Quiet) -and (Test-WSMan -ComputerName $computer -ErrorAction Ignore))
{
#https://ss64.com/ps/syntax-functions.html
$scriptblock = $executioncontext.InvokeCommand.NewScriptBlock(${function:Enable-CommonAreaPhones})
Invoke-Command -Session $allsession -ScriptBlock $scriptblock -ArgumentList $R_LineURI,$R_RegistrarPool, $R_OU_CommonArea, $R_Description, $R_DisplayName, $R_DisplayNumber,$R_SIP -ErrorVariable errorMsg
Invoke-Command -Session $allsession -ScriptBlock ${function:Enable-CommonAreaPhones} -ArgumentList $R_LineURI,$R_RegistrarPool, $R_OU_CommonArea, $R_Description, $R_DisplayName, $R_DisplayNumber,$R_SIP -ErrorVariable errorMsg
$RemoteFEComputerCompletedSuccessfull = $true
}
}
}
I'm having some difficulties passing the switch -CleanFolders to a function by using Invoke-Command. I found this, but I don't really know how to implement it as it's not targeted to a function.
Calling my function like this works fine:
Delete-OldFiles $Target $OlderThanDays $Server -CleanFolders
Invoke-Command -ComputerName "$Server" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
But this doesn't work at all:
Invoke-Command -ComputerName "$Server" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server, -CleanFolders)
Full script:
#__________________________________________________________________________________________________________________________________
$ImportFile = "S:\Input\Scheduled Task\Auto_Clean.csv"
$Password = cat "S:\Input\pwd.txt" | ConvertTo-SecureString -Force
$UserName = "domain\me"
#__________________________________________________________________________________________________________________________________
# Scriptblock for running the function in a job
$JobFunc = {
# Function that removes files older than x days in all subfolders
Function Delete-OldFiles {
<#
.SYNOPSIS
Script to delete files and folders older than x days
.DESCRIPTION
Remove files older than x days in all subfolders and write success and failure actions to the logfile in "\\DEUSTHEIDIT02\Log\Scheduled Task\Auto_Clean\".
By default, empty foldes will be left behind and not deleted.
.PARAMETER Target
The path that will be recusively scanned for old files
.PARAMETER OlderThanDays
Filter for age of file, entered in days. Use 0 for all files to be removed
.PARAMETER CleanFolders
If this switch is specified folders that are older than 'OlderThanDays' and are empty will be removed. Default behaviour of this script is to leave empty folders behind.
.EXAMPLE
Delete-OldFiles -Target "\\grouphc.net\bnl\DEPARTMENTS\Brussels\CBR\SHARE\Target" -OlderThanDays "10"
Delete-OldFiles "\\grouphc.net\bnl\DEPARTMENTS\Brussels\CBR\SHARE\Target" "10"
Delete-OldFiles "E:\DEPARTMENTS\CBR\SHARE\Target" "10"
Description:
Deletes all files older than 10 days in the Target folder and all of its subfolders and write success and failure to the log.
.EXAMPLE
Delete-OldFiles "\\grouphc.net\bnl\DEPARTMENTS\Brussels\CBR\SHARE\Target" "10" -CleanFolders
Description:
Deletes all files older than 10 days and all empty folders in the Target folder and all of its subfolders and write success and failure to the log.
.NOTES
REQUIREMENTS Remote server:
PowerShell 2.0
As admin run 'Set-ExecutionPolicy RemoteSigned'
As amdin run 'Enable-WSManCredSSP -Role Server -Force'
REQUIREMENTS Script server:
Enable-WSManCredSSP -Role Client -DelegateComputer *.grouphc.net -Force
CHANGELOG
2014/05/06 Script born
2014/05/07 Added total runtime of the script to the logfile
2014/05/12 Added timestamps, fail and success messages to the logfile
2014/05/13 Added PowerShell 2.0 compatibility for Windows Server 2003
2014/05/13 Added remove empty directories
2014/05/14 Added comment section on top
2014/05/15 Added parameters to pass variables $Target and $OlderThanDays
2014/05/19 Added CSV input file for easy management
2014/05/20 Created function Delete-OldFiles and Delete-OldFolders
2014/05/22 Rewrote script for calling functions
2014/05/23 Added switch -CleanFolders
2014/06/02 Added password authentication for double hop
2014/06/03 Added loging capability to different files with timestamps
.AUTHOR
Me #>
[CmdletBinding(SupportsShouldProcess=$True)] # Add -WhatIf support for dry run
Param(
[Parameter(Mandatory=$True,Position=1)]
[ValidateScript({Test-Path $_})]
[String]$Target,
[Parameter(Mandatory=$True,Position=2)]
[Int]$OlderThanDays,
[Parameter(Mandatory=$False,Position=3)]
[String]$Server,
[switch]$CleanFolders
)
#__________________________________________________________________________________________________________________________________
# Create logfile with the correct name
# Gets date and reformats to be used in log filename
$TempDate = (get-date).ToString("dd-MM-yyyy")
# Reformats $Target so it can be used in the log filename
$TempFolderPath = $Target -replace '\\','_'
$TempFolderPath = $TempFolderPath -replace ':',''
$TempFolderPath = $TempFolderPath -replace ' ',''
# Combines the date and the path scanned into the log filename
$script:LogFile = "\\DEUSTHEIDIT02\Log\Scheduled Task\Auto_Clean\$Server - $TempFolderPath - $TempDate.log"
#__________________________________________________________________________________________________________________________________
# Check the version of PowerShell
if ($PSVersionTable.PSVersion.Major -ge "3") {
# PowerShell 3+ Remove files older than (FASTER)
Get-ChildItem -Path $Target -Recurse -File |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
"$Timestamp | REMOVED: $Server $Item"
}
} | Tee-Object $LogFile -Append }
Else {
# PowerShell 2 Remove files older than
Get-ChildItem -Path $Target -Recurse |
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
Write-Host "$Timestamp | FAILLED: $Server $Item (IN USE)"
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
Write-Host "$Timestamp | REMOVED: $Server $Item"
"$Timestamp | REMOVED: $Server $Item"
}
} | Out-File $LogFile -Append }
#__________________________________________________________________________________________________________________________________
# Switch -CleanFolders deletes empty folders older than x days
if ($CleanFolders) {
# Check the version of PowerShell
if ($PSVersionTable.PSVersion.Major -ge "3") {
# PowerShell 3+ Remove empty folders older than (FASTER)
Get-ChildItem -Path $Target -Recurse -Force -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
Where-Object { (Get-ChildItem -Path $_.FullName -Recurse -Force -File) -eq $null } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
"$Timestamp | REMOVED: $Server $Item"
}
} | Tee-Object $LogFile -Append
}
else {
# PowerShell 2 Remove empty folders older than
Get-ChildItem -Path $Target -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
Write-Host "$Timestamp | FAILLED: $Server $Item (IN USE)"
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
Write-Host "$Timestamp | REMOVED: $Server $Item"
"$Timestamp | REMOVED: $Server $Item"
}
} | Out-File $LogFile -Append
}
}
}
}
#__________________________________________________________________________________________________________________________________
# Read input file and ignore all lines starting with #
$File = (Import-Csv -Path $ImportFile -Header "Server", "Target", "OlderThanDays" | Where { $_.Server -NotMatch "#" } )
#__________________________________________________________________________________________________________________________________
# If the UNC Path is provided we will run the script locally else it wil be run on the remote server as a job
Foreach ($_ in $File) {
# Set easy names
$Server = $_.Server
$Target = $_.Target
$OlderThanDays = $_.OlderThanDays
if ($Server -eq "UNC")
{
Write-Host "UNC Path detected: $Target, $OlderThanDays" -ForegroundColor Yellow
Start-Job -ScriptBlock {Param($Target, $OlderThanDays, $Server) Delete-OldFiles $Target $OlderThanDays $Server} -InitializationScript $JobFunc -ArgumentList ($Target, $OlderThanDays, $Server) -Name DelFiles
# Remove empty folders to: Delete-OldFiles $Target $OlderThanDays $Server -CleanFolders
}
else
{
Write-Host "Local path detected: $Server, $Target, $OlderThanDays" -ForegroundColor Cyan
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$Password
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$Password
Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {$JobFunc; Delete-OldFiles $Target $OlderThanDays $Server} -ArgumentList ($Target, $OlderThanDays, $Server) #-AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {Delete-OldFiles $args[0] $args[1] $args[2] -CleanFolders:$args[3]} -ArgumentList ($Target, $OlderThanDays, $Server, $true) -AsJob -JobName DelFiles
# Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server) -AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {Delete-OldFiles $Target, $OlderThanDays, $Server} -ArgumentList ($Target, $OlderThanDays, $Server) #-AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server) #-AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {$JobFunc} -ArgumentList ($Target, $OlderThanDays, $Server) -AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
}
}
Thank you for your help.
Try like this:
$sb = {
function Delete-OldFiles {
#...
}
Delete-OldFiles $args[0] $args[1] $args[2] -CleanFolders:$args[3]
}
Invoke-Command -ComputerName $Server -Authentication Credssp `
-Credential $Credentials -ScriptBlock $sb `
-ArgumentList ($Target, $OlderThanDays, $Server, $true)