I have a question i wrote a powershell script so i have name.ps1, but i have troubles for executing it, i mean i could debut it with windows powershell (ISE), by just adding the code to it and run ... but how do i execute it different?
When i open ordinary windows powershell (so NOT ISE) and i type there script.ps1 file.csv
i get this kind of error:
This is the code that i have, maybe im not proper initiating the script in my code i dont know:
param ([string]$Csv)
function GetHelp() {
$HelpText = #"
DESCRIPTION:
NAME: Add-STUser
Adds Users from the User Csv File
PARAMETERS:
-Csv The Csv file Used by the script (Required)
-help Prints the HelpFile (Optional)
The Csv File is built up in the following way:
Firstname, Surname, Email
"#
$HelpText
}
function Get-Csv ([string]$Csv) {
$CsvFile = Import-Csv $Csv
$CsvFile | ForEach {
Add-User -Firstname $_.Firstname -Surname $_.Surname -Email $_.Email
}
}
function Add-User ([string]$Firstname, [string]$Surname, [string]$Email) {
# Set up AD Connectionstring
# Get A Unique Password
[string]$Password = Generate-Password
$username=$Firstname.substring(0,1).toLower() + $Surname.toLower()
# Create User in AD
$container =[ADSI] $Connection
$User = $container.Create("User", "cn="+$username)
$User.Put("sAMAccountName", $username)
$User.Put("givenName", $Firstname)
$User.Put("sn", $Surname)
$User.Put("mail", $Email)
$User.Put("displayName", $Firstname + " "+$Surname)
$User.SetInfo()
# Set Random Pwd and Enable Account
$User.PsBase.Invoke("SetPassword", $Password)
$User.PsBase.InvokeSet("AccountDisabled", $false)
$User.pwdLastSet = 0
$User.SetInfo()
# Write Pwd to File
$FileName = "PasswordList " + (get-date -uformat "%Y-%m-%d") + ".txt"
"$Firstname, $Surname, $username, $email, $Password" | Add-Content $FileName
Write-Host "Added User: $username" -ForegroundColor Green
# Set Check Variable to False
$Password = $Null
#$Script:sAMAccountNameDoesntExist = $False
#$Script:distinguishedNameDoesntExist = $False
}
if ($help) {
GetHelp
} elseif ($Domain -AND $Csv) {
Get-Csv -Csv $Csv
} else {
GetHelp
}
So with other words i need to execute that script with only 1 param (path to csv file)
Thanks in advance
In Powershell, unlike cmd, current directory (.) is not in PATH.
So to run scripts or executables in the current directory, you have to prefix with ./
So you will have to do
.\script.ps1 file.csv
If you look carefully at the error message, at the bottom, Powershell is giving a suggestion that you have to do so.
You need to tell Powershell you want to execute a script from current location, like in *nix systems. So call the script like the error message hints:
./myScript.ps1
or
.\myScript.ps1
You can also provide full path to the script
c:\what\ever\is\the\path\myScript.ps1
The script/directory names are not case sensitive.
Related
In Octopus deploy I have added a step in process to run the stored procedure with library script “SQL - Execute Scripts Ordered step”.
When I’m providing the script to execute the stored procedure it is throwing the below Exception:
Exception calling “ReadAllText” with “1” argument(s): “The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.”
Closing connection
I believe this is because of the large script as text I've provided to execute in field “SQL Script File”.
As shown in examples I can run script directly. So I’m providing the stored procedure execution script but in library's PowerShell scipt -
$content = [IO.File]::ReadAllText($OctopusParameters[‘SqlScriptFile’])
ReadAllText is expecting something less than 260 characters.
One solution I can think of is to provide the execution script as a file within package itself. But this will be the last resort.
How can I run the stored procedure directly from the step in process?
Apparantly [IO.File]::ReadAllText($OctopusParameters[‘SqlScriptFile’]) is expecting file path as SqlScriptFile. I updated the library's powershell script to take the full sql script from field "SQL Script File" as parameter and passed it directly to the function.
$content= $OctopusParameters['SqlScriptFile']
Execute-SqlQuery -query $content
providing below the full powershell script for reference:
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $OctopusParameters['ConnectionString']
Register-ObjectEvent -inputobject $connection -eventname InfoMessage -action {
write-host $event.SourceEventArgs
} | Out-Null
function Execute-SqlQuery($query) {
$queries = [System.Text.RegularExpressions.Regex]::Split($query, "^\s*GO\s*`$", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Multiline)
$queries | ForEach-Object {
$q = $_
if ((-not [String]::IsNullOrWhiteSpace($q)) -and ($q.Trim().ToLowerInvariant() -ne "go")) {
$command = $connection.CreateCommand()
$command.CommandText = $q
$command.CommandTimeout = $OctopusParameters['CommandTimeout']
$command.ExecuteNonQuery() | Out-Null
}
}
}
Write-Host "Connecting"
try {
$connection.Open()
Write-Host "Executing script in" $OctopusParameters['SqlScriptFile']
# $content = [IO.File]::ReadAllText($OctopusParameters['SqlScriptFile'])
$content= $OctopusParameters['SqlScriptFile']
Execute-SqlQuery -query $content
}
catch {
if ($OctopusParameters['ContinueOnError']) {
Write-Host $_.Exception.Message
}
else {
throw
}
}
finally {
Write-Host "Closing connection"
$connection.Dispose()
}
This is a little difficult to explain, but I will do my best. I am writing some code to import AD contacts to users' mailboxes through EWS using Powershell.
I have a Main.ps1 file that calls all the other scripts that do work in the background (for example 1 imports the AD modules) another imports O365 modules.
I have 1 script container that connect to EWS. The code looks like this:
#CONFIGURE ADMIN CREDENTIALS
$userUPN = "User#domain.com"
$AESKeyFilePath = ($pwd.ProviderPath) + "\ConnectToEWS\aeskey.txt"
$SecurePwdFilePath = ($pwd.ProviderPath) + "\ConnectToEWS\password.txt"
$AESKey = Get-Content -Path $AESKeyFilePath -Force
$securePass = Get-Content -Path $SecurePwdFilePath -Force | ConvertTo-SecureString -Key $AESKey
#create a new psCredential object with required username and password
$adminCreds = New-Object System.Management.Automation.PSCredential($userUPN, $securePass)
Try
{
[Reflection.Assembly]::LoadFile("\\MBX-Server\c$\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll") | Out-Null
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($userUPN,$adminCreds.GetNetworkCredential().Password)
$service.Url = new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx");
return $service
}
Catch
{
Write-Output "Unable to connect to EWS. Make sure the path to the DLL or URL is correct"
}
The output of that code prints out the Service connection, but I want the information for that output stored in a variable such as $service.
Then I would pass that variable to another script that binds to the mailbox I want...
The problem I am having is $service doesn't seem to be storing that information. It only print it out once when I return it from the script above, but it doesn't append that information in the main script. When I print out $service it prints out once, but then it clears itself.
Here is my main script
CLS
#Root Path
$rootPath = $pwd.ProviderPath #$PSScriptRoot #$pwd.ProviderPath
Write-Host "Importing all necessary modules."
#******************************************************************
# PREREQUISITES
#******************************************************************
#Nuget - Needed for O365 Module to work properly
if(!(Get-Module -ListAvailable -Name NuGet))
{
#Install NuGet (Prerequisite) first
Install-PackageProvider -Name NuGet -Scope CurrentUser -Force -Confirm:$False
}
#******************************************************************
#Connect w\ Active Directory Module
& $rootPath\AD-Module\AD-module.ps1
#Load the O365 Module
& $rootPath\O365-Module\O365-module.ps1
#Clear screen after loading all the modules/sessions
CLS
#******************************************************************
# PUT CODE BELOW
#******************************************************************
#GLOBAL VARIABLES
$global:FolderName = $MailboxToConnect = $Service = $NULL
#Connect to EWS
& $rootPath\ConnectToEWS\ConnectToEWS.ps1
#Debug
$Service
#Create the Contacts Folder
& $rootPath\CreateContactsFolder\CreateContactsFolder.ps1
#Debug
$service
$ContactsFolder
#Clean up Sessions after use
if($NULL -ne (Get-PSSession))
{
Remove-PSSession *
}
[GC]::Collect()
The first time I output the $service variable, it prints fine. In the 2nd Debug output it doesn't print out anymore, and I believe that it why the script is failing when I launch "CreateContactsFolder.ps1"
Here is the content of "CreateContactsFolder.ps1"
CLS
Try
{
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxToConnect);
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
$RootFolder.Load()
#Check to see if they have a contacts folder that we want
$FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where-Object {$_.DisplayName -eq $FolderName}
if($ContactsFolderSearch)
{
$ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);
#If folder exists, connect to it. Clear existing Contacts, and reupload new (UPDATED) Contact Info
Write-Output "Folder alreads exists. We will remove all contacts under this folder."
# Attempt to empty the target folder up to 10 times.
$tries = 0
$max_tries = 0
while ($tries -lt 2)
{
try
{
$tries++
$ErrorActionPreference='Stop'
$ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
$tries++
}
catch
{
$ErrorActionPreference='SilentlyContinue'
$rnd = Get-Random -Minimum 1 -Maximum 10
Start-Sleep -Seconds $rnd
$tries = $tries - 1
$max_tries++
if ($max_tries -gt 100)
{
Write-Output "Error; Cannot empty the target folder; `t$EmailAddress"
}
}
}
}
else
{
#Contact Folder doesn't exist. Let's create it
try
{
Write-Output "Creating new Contacts Folder called $FolderName"
$ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service);
$ContactsFolder.DisplayName = $FolderName
$ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
}
catch
{
Write-Output "Error; Cannot create the target folder; `t$EmailAddress"
}
}
}
Catch
{
Write-Output "Couldn't connect to the user's mailbox. Make sure the admin account you're using to connect to has App Impersonization permissions"
Write-Output "Check this link for more info: https://help.bittitan.com/hc/en-us/articles/115008098447-The-account-does-not-have-permission-to-impersonate-the-requested-user"
}
return $ContactsFolder
In the Main script, capture the returned variable from the EWS script like
$service = & $rootPath\ConnectToEWS\ConnectToEWS.ps1
Or dot-source that script into the Main script, so the variables from EWS.ps1 are local to the Main script, so you don't need to do return $service in there:
. $rootPath\ConnectToEWS\ConnectToEWS.ps1
and do the same for the CreateContactsFolder.ps1 script
OR
define the important variables in the called scripts with a global scope $global:service and $global:ContactsFolder
See About_Scopes
I'm just a typical admin trying to make a simple script for some IT assistants in remote offices, to make domain joins easier while minimizing potential errors. The script's end game is to run the one-liner command Add-Computer -DomainName $DomainToJoin -OUPath $LocDN -NewName $WS_NewName -Restart.
But the whole script is supposed to include input validation for the computer's new name as well as for the target OU for the two-letter code for the remote office.
Googling for code snippets for days, esp. from sites like yours, was very helpful. But the problem I have now is I couldn't find the right codes to combine Read-Host , input length validation, and TRAP to work together without losing the value for my variables.
Pardon my coding as obviously I'm no real PS scripter, and I know the wrong portions of it are very basic. I would want to spend more time if I had the luxury, but I would really so much appreciate it if you could point me in the right direction.
Thank you so much in advance.
Please see my code below:
# START: Display name and purpose of invoked script
$path = $MyInvocation.MyCommand.Definition
Clear-Host
Write-Host $path
Write-Host " "
Write-Host "This script will allow you to do the following in a single-step process:"
Write-Host "(1) RENAME this computer"
Write-Host "(2) JOIN it to MYDOMAIN"
Write-Host "(3) MOVE it to a target OU"
Write-Host "(4) REBOOT"
Write-Host " "
Pause
# Function: PAUSE
Function Pause ($Message = "Press any key to continue . . . ") {
if ((Test-Path variable:psISE) -and $psISE) {
$Shell = New-Object -ComObject "WScript.Shell"
$Button = $Shell.Popup("Click OK to continue.", 0, "Script Paused", 0)
}
else {
Write-Host -NoNewline $Message
[void][System.Console]::ReadKey($true)
Write-Host
}
Write-Host " "
}
# Function: Define the parameters
Function Define-Parameters {
# Specify new computer name, with validation and TRAP
$WS_NewName = $null
while ($null -eq $WS_NewName) {
[ValidateLength(8,15)]$WS_NewName = [string](Read-Host -Prompt "NEW NAME of computer (8-15 chars.)" )
TRAP {"" ;continue}
}
Write-Host " "
# Domain to join.
$DomainToJoin = 'mydomain.net'
# Specify the target OU, with validation and trap
$baseOU='OU=Offices OU,DC=mydomain,DC=net'
$OU2 = $null
while ($null -eq $OU2) {
[ValidateLength(2,2)]$OU2 = [string](Read-Host -Prompt 'Target OU (TWO-LETTER code for your office)' )
TRAP {"" ;continue}
}
Write-Host " "
$LocDN = "OU=$OU2,$baseOU"
}
# Function: Summary and confirmation screen for defined parameters.
Function Confirm-Parameters {
Write-Host "==========================================================================="
Write-Host "Please confirm that you are joining this computer to
$DomainToJoin (MYDOMAIN)"
Write-Host "with the following parameters:"
Write-Host ""
Write-Host ""
Write-Host "Computer's NEW NAME: $WS_NewName"
# Write-Host "Domain to Join: $DomainToJoin"
Write-Host "TARGET mission OU: $OU2"
}
# Call Define-Parameters Function
Define-Parameters
# Call Confirm-Parameters Function
Confirm-Parameters
<#
Some more code here
#>
# FINAL COMMAND if all else works: Join the computer to the domain, rename it, and restart it.
# Add-Computer -DomainName $DomainToJoin -OUPath $LocDN -NewName $WS_NewName -Restart
In your code, you have a lot of things defined very strangely. Your functions create a new scope and the variables you're trying to define therein will disappear after calling them unless you change the variable scope (in this case, to $script: or $global:). Also, to use functions, you need to define them first (your Pause doesn't actually do anything)
Here's something you can do with your Define-Parameters function (I suggest looking at Get-Verb)
# Domain to join.
$DomainToJoin = 'mydomain.net'
# Function: Define the parameters
Function Get-Parameters {
do {
$global:WS_NewName = Read-Host -Prompt 'NEW NAME of computer (8-15 chars)'
} until ($WS_NewName.Length -gt 7 -and $WS_NewName.Length -lt 16)
''
do {
$global:OU2 = Read-Host -Prompt 'Target OU (TWO-LETTER code for your office)'
} until ($OU2 -match '^[a-z]{2}$')
''
$OU2 = "OU=$global:OU2,OU=Offices OU,DC=mydomain,DC=net"
}
I'd strongly recommend moving away from the ISE to do your testing and test in an actual powershell console.
Perhaps Try/Catch block instead of trap?
Try {
[ValidatePattern('^\w{8,15}$')]$compname=read-host 'enter comp name' -ErrorAction Stop
[ValidatePattern('^\w{2}$')]$OU=read-host 'enter OU name' -ErrorAction Stop
}
Catch {
$ErrorMessage = $_.Exception.Message
$ErrorLineNumber = $_.InvocationInfo.ScriptLineNumber
$ErrorCommandName = $_.InvocationInfo.InvocationName
Write-Error -Message "The error message was: <$ErrorMessage>, script line: <$ErrorLineNumber>, command name: <$ErrorCommandName>"
exit 255
}
I am looking for way to speed up my Powershell script. I have a script that returns the manager Employee ID and manager name based on a .txt file that has the samaccountnames for each user under that manager. The problem is the list is very long, about 1400+ names and the script is taking forever to run. Here is my script. It works, just looking for a way to speed it up:
cls
If (!(Get-Module -Name activerolesmanagementshell -ErrorAction SilentlyContinue))
{
Import-Module activerolesmanagementshell
}
Write-host $("*" * 75)
Write-host "*"
Write-host "* Input file should contain just a list of samaccountnames - no header row."
Write-host "*"
Write-host $("*" * 75)
$File = Read-Host -Prompt "Please supply a file name"
If (!(test-path $File))
{
Write-host "Sorry couldn't find the file...buh bye`n`n"
exit
}
get-content $File | %{
$EmpInfo = get-qaduser -proxy -Identity $_ -IncludedProperties employeeid,edsva_SSCOOP_managerEmployeeID
# Check if we received back a Manager ID - if yes, get the Manager's name
# If not, set the Manager Name to "NONE" for output
If ($($EmpInfo.edsva_SSCOOP_managerEmployeeID).length -gt 2)
{
# Get the Manager's name from AD
$($EmpInfo.edsva_SSCOOP_managerEmployeeID)
$ManagerName = $(Get-QADUser -SearchAttributes #{employeeid=$($EmpInfo.edsva_SSCOOP_managerEmployeeID)} | select name).name
If (!$ManagerName)
{
$ManagerName = "NONE"
}
# Add the Manager name determined above (or NONE) to the properties we'll eventually output
$EmpInfo | Add-Member -MemberType NoteProperty -Name ManagerName -Value $ManagerName
}
Else
{
$EmpInfo.edsva_SSCOOP_managerEmployeeID = "NONE"
}
# Output user samaccountname edsva_SSCOOP_managerEmployeeID and ManagerName to a file
$EmpInfo | select samaccountname,edsva_SSCOOP_managerEmployeeID,ManagerName | export-csv "C:\Users\sfp01\Documents\Data_Deletion_Testing\Script_DisaUser_MgrEmpID\Disabled_Users_With_Manager.txt" -NoTypeInformation -Append
} # End of file processing loop
Ok, first things first... asking your user to type in a file name. Give them a nice friendly dialog box with little effort. Here's a function I keep on hand:
Function Get-FilePath{
[CmdletBinding()]
Param(
[String]$Filter = "All Files (*.*)|*.*|Comma Seperated Values (*.csv)|*.csv|Text Files (*.txt)|*.txt",
[String]$InitialDirectory = $home,
[String]$Title)
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $InitialDirectory
$OpenFileDialog.filter = $Filter
$OpenFileDialog.Title = $Title
[void]$OpenFileDialog.ShowDialog()
$OpenFileDialog.filename
}
Then you can do:
$File = Get-FilePath -Filter 'Text Files (*.txt)|*.txt|All Files (*.*)|*.*' -InitialDirectory "$home\Desktop" -Title 'Select user list'
That doesn't speed things up, it's just a quality of life improvement.
Secondly, your 'can't find the file' message will appear as the window closes, so the person that ran your script probably won't see it. Towards that end I have a function that I use to pause a script with a message.
Function Invoke-Pause ($Text){
[reflection.assembly]::LoadWithPartialName('Windows.Forms')|out-null
If($psISE){
[Windows.Forms.MessageBox]::Show("$Text", "Script Paused", [Windows.Forms.MessageBoxButtons]"OK", [Windows.Forms.MessageBoxIcon]"Information") | ?{(!($_ -eq "OK"))}
}Else{
Write-Host $Text
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}
With that you can get a message to the user, and then close the script so the user knows what happened. This function works in both the PowerShell console, as well as in the PowerShell ISE. In the console you get a text message that you define, and then a 'Press any key to continue...' message, and it waits for the user to press a key. In the ISE it pops up a window with your message, and waits for the user to click the OK button before proceeding. You could do something like:
If(!(Test-Path $File)){Invoke-Pause "Sorry couldn't find the file...buh bye";exit}
Now to get on to speeding things up!
You have more than one employee per manager right? So why look up the manager more than once? Setup a hashtable to keep track of your manager info, and then only look them up if you can't find them in the hashtable. Before your loop declare $Managers as a hashtable that just declares that 'NONE' = 'NONE', then inside the loop populate it as needed, and then reference it later.
Also, you are appending to a file for each user. That means PowerShell has to get a file lock on the file, write to it, close the file, and release the lock on it... over and over and over and over... Just pipe your users down the pipeline and write to the file once at the end.
Function Get-FilePath{
[CmdletBinding()]
Param(
[String]$Filter = "All Files (*.*)|*.*|Comma Seperated Values (*.csv)|*.csv|Text Files (*.txt)|*.txt",
[String]$InitialDirectory = $home,
[String]$Title)
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $InitialDirectory
$OpenFileDialog.filter = $Filter
$OpenFileDialog.Title = $Title
[void]$OpenFileDialog.ShowDialog()
$OpenFileDialog.filename
}
cls
If (!(Get-Module -Name activerolesmanagementshell -ErrorAction SilentlyContinue))
{
Import-Module activerolesmanagementshell
}
Write-host $("*" * 75)
Write-host "*"
Write-host "* Input file should contain just a list of samaccountnames - no header row."
Write-host "*"
Write-host $("*" * 75)
$File = Get-FilePath -Filter 'Text Files (*.txt)|*.txt|All Files (*.*)|*.*' -InitialDirectory "$home\Desktop" -Title 'Select user list'
If (!(test-path $File))
{
Write-host "Sorry couldn't find the file...buh bye`n`n"
exit
}
$Managers = #{'NONE'='NONE'}
Get-Content $File | %{
$EmpInfo = get-qaduser -proxy -Identity $_ -IncludedProperties employeeid,edsva_SSCOOP_managerEmployeeID
Switch($EmpInfo.edsva_SSCOOP_managerEmployeeID){
{$_.Length -lt 2} {$EmpInfo.edsva_SSCOOP_managerEmployeeID = 'NONE'}
{$_ -notin $Managers.Keys} {
$MgrLookup = Get-QADUser -SearchAttributes #{employeeid=$EmpInfo.edsva_SSCOOP_managerEmployeeID} |% Name
If(!$MgrLookup){$MgrLookup = 'NONE'}
$Managers.add($EmpInfo.edsva_SSCOOP_managerEmployeeID,$MgrLookup)
}
}
Add-Member -InputObject $EmpInfo -NotePropertyName 'ManagerName' -NotePropertyValue $Managers[$EmpInfo.edsva_SSCOOP_managerEmployeeID] -PassThru
} | select samaccountname,edsva_SSCOOP_managerEmployeeID,ManagerName | Export-Csv "C:\Users\sfp01\Documents\Data_Deletion_Testing\Script_DisaUser_MgrEmpID\Disabled_Users_With_Manager.txt" -NoTypeInformation -Append
Alrighty, so I've got this much down.
# Prompts the script user to confirm that the account from
# $userName is indeed the one they want to Terminate
function Get-Confirmation {
[CmdletBinding(SupportsShouldProcess=$true)]
param (
[Parameter(Mandatory=$true)]
[String]
$userName
)
$confirmMessage = 'Are you sure that {0} is the user that you want to terminate?' -f $userName
$PSCmdlet.ShouldContinue($confirmMessage, 'Terminate User?')
}
# Code that populates $userName and starts the Termination process
if (Get-Confirmation -User $userName) {
# If confirmation == True: start Termination
# Copy user's security groups to $groups.txt in their user folder
Out-File $logFilePath -InputObject $userNameGroups.memberOf -Encoding utf8
# TODO: Remove $userName's security groups from AD Object
# Remove-ADGroupMember -Identity $_ -Members $userNameGroups -Confirm:$false
Copy-Item -Path "\\path\to\active\user\folder" `
-Destination "\\path\to\terminated\user\folder"
} else {
# Don't Terminate
# TODO: Restart script to select another user
}
So my question is: how do I satisfy the TODO in the else statement? I've searched online, but the only thing that has come up is restarting the computer. I just want the script to be re-run. Is it as simple as ./scriptName?
Rather than "Restarting" your script you could check that the input is correct before even "Starting" your script, if all the input is correct there won't be any need to "Restart" :)
Here a Do-While loop is used to check that a username exists in AD before proceeding to the script below:
$message = "Please enter the username you'd like to terminate"
Do
{
# Get a username from the user
$getUsername = Read-Host -prompt $message
Try
{
# Check if it's in AD
$checkUsername = Get-ADUser -Identity $getUsername -ErrorAction Stop
}
Catch
{
# Couldn't be found
Write-Warning -Message "Could not find a user with the username: $getUsername. Please check the spelling and try again."
# Loop de loop (Restart)
$getUsername = $null
}
}
While ($getUsername -eq $null)
# Do-While succeeded so username is correct
# Put script to run if input is correct here