I've created a powershell script that removes all licences and group memberships from a person when he/she is leaving the company and adds an automatic reply to their mailbox. Everything else is going fine, except when i added Scandinavian letters into the hardcoded auto-reply.
bold The error is only for hard coded data. Everything that is prompted is read correctly
if ( "y" -eq $Automaattivastaus) {
$Username = Read-Host -Prompt "Nimi automaattivastaukseen"
$Paivamaara = Read-Host -Prompt "Milloin henkilön työsuhde on päättynyt?"
$Vastaanottaja = Read-Host -Prompt "automaattivastaus, Mihin sähköpostiin ottaa yhteyttä"
set-MailboxAutoReplyConfiguration -identity $Email -AutoReplyState Enabled -InternalMessage "Henkilön $Username palvelussuhde on päättynyt $Paivamaara. Pyydän kääntymään hänen työtehtäviensä hoitoon liittyvissä asioissa sovelletaan Lakia yksityisyyden suojasta työelämässä (759/2004)."
"snippet from auto reply Pyydän kääntymään hänen työtehtäviensä hoitoon liittyvissä asioissa."
As you can see the characters break. If anyone would have the solution how to fix this I would be grateful.
Connect-ExchangeOnline -UserPrincipalName "my.account#test.com" -ShowProgress $true
Add-Type -AssemblyName system.web
$Username = "Täältä pesee! Härifrån tvättas!"
$Paivamaara = "15.06.2021"
$Vastaanottaja = "Öland"
$Email = "test.account#test.com"
$Automaattivastaus = "Henkilön $Username palvelussuhde on päättynyt $Paivamaara. Pyydän kääntymään hänen työtehtäviensä hoitoon liittyvissä asioissa
($Vastaanottaja) puoleen. Mikäli viestisi on luonteeltaan yksityisluontainen, pyydän ottamaan yhteyttä suoraan henkilöön $Username. Yksityisluontaiset viestit tuhotaan ilman niiden avaamista. Työhön liittyvien viestien selvittämiseen ja avaamiseen
sovelletaan Lakia yksityisyyden suojasta työelämässä (759/2004)."
$t = [web.httputility]::Htmldecode($Automaattivastaus)
set-MailboxAutoReplyConfiguration -identity $Email -AutoReplyState Enabled -InternalMessage ([web.httputility]::Htmldecode($t)) -ExternalMessage ([web.httputility]::Htmldecode($t))
I don't have Exchange available, so I can't check this. Anyway, since ExternalMessage wraps the message automatically within HTML tags, try and convert the string into HTML escaped form. That will escape åäö and other characters that need escaping in HTML. Like so,
# Load assembly that contains the utility class
add-type -AssemblyName system.web
# A demo string with Finnish and Swedish letters
$s = "Täältä pesee! Härifrån tvättas!"
# Encode the string.
$t = [web.httputility]::HtmlEncode($s)
$t
Täältä pesee! Härifrån tvättas!
# The encoding is reversable, obviously.
[web.httputility]::Htmldecode($t)
Täältä pesee! Härifrån tvättas!
Edit:
Call the ENcode version, it will convert ääkköset into escped forms. the DEcode will reverse the encoding. It is not needed here, and was included as for illustration purposes only. Like so,
$Automaattivastaus = "Henkilön $Username palvelussuhde on päättynyt $Paivamaara..."
$encodedAnswer = [web.httputility]::HtmlEncode($Automaattivastaus)
set-MailboxAutoReplyConfiguration -identity $Email -AutoReplyState Enabled -InternalMessage $encodedAnswer -ExternalMessage $encodedAnswer
What if you would enclose the message in quotation marks and set the encoding?
$Username = Read-Host -Prompt "Nimi automaattivastaukseen"
$Paivamaara = Read-Host -Prompt "Milloin henkilön työsuhde on päättynyt?"
$Vastaanottaja = Read-Host -Prompt "automaattivastaus, Mihin sähköpostiin ottaa yhteyttä"
$message = "<html><head><meta charset='UTF-8'></head>
<body>
Henkilön $Username palvelussuhde on päättynyt $Paivamaara. Pyydän kääntymään hänen työtehtäviensä hoitoon liittyvissä asioissa sovelletaan Lakia yksityisyyden suojasta työelämässä (759/2004).
</body>
</html>"
set-MailboxAutoReplyConfiguration -identity $Email -AutoReplyState Enabled -InternalMessage $message
I'm no expert in either PowerShell or Exchange but this might help you.
I'm using powershell to transfer data to my server.
I had an original question here: Powershell downloadFile with special characters about trying to escape a string inside of batch, which I had no luck with. So I created the short powershell script here:
$model = $args[0]
$os = $args[1]
$gpu = $args[2]
$hdd = $args[3]
$ram = $args[4]
$processor = $args[5]
$realmodel = $args[6]
$realupc = $args[7]
$productnumber = $args[8]
$url = [uri]::EscapeUriString("http://example.com/otherdb/modelfinder/form.php?model=$model&os=$os&graphics=$gpu&hdd=$hdd&ram=$ram&processor=$processor&actualmodel=$realmodel&Implement=0&UPC=$realupc&otherIdentifier=$productnumber")
(New-Object Net.WebClient).DownloadFile($url, 'save.txt')
Which successfully escapes the string and sends it to my server to be processed.
The problem is, near the end of my url, there is sometimes a pound sign # - which I believe powershell may be counting as a comment, or simply isn't being encoded. When checking my database after the url is sent, the # and everything after it is removed from the cell.
How can I encode the string to be sent exactly the way it is to be saved in my database?
You should escape your arguments separately as data strings. When you use [uri]::EscapeUriString("#") you will see that # will not be escaped.
PS > [uri]::EscapeUriString("#");
#
PS > [uri]::EscapeDataString("#")
%23
So as an abbreviated example, you could construct your string like this:
$sb = [System.Text.StringBuilder]::new();
$model = "# model with hash sign"
$os = "some operating system with exclamation mark!!";
$sb.Append("http://example.com/otherdb/modelfinder/form.php?model=");
$sb.Append([uri]::EscapeDataString($model).ToString());
$sb.Append("&os=");
$sb.Append([uri]::EscapeDataString($os).ToString());
$sb.ToString();
http://example.com/otherdb/modelfinder/form.php?model=%23%20model%20with%20hash%20sign&os=some%20operating%20system%20with%20exclamation%20mark!!
I have the following PowerShell script that creates a random string of 15 digits, for use as an Active Directory password.
The trouble is, this works great most of the time, but on some occasions it doesn't use a number or symbol. I just get 15 letters. This is then not usable as an Active Directory password, as it must have at least one number or symbol in it.
$punc = 46..46
$digits = 48..57
$letters = 65..90 + 97..122
$YouShallNotPass = get-random -count 15 `
-input ($punc + $digits + $letters) |
% -begin { $aa = $null } `
-process {$aa += [char]$_} `
-end {$aa}
Write-Host "Password is $YouShallNotPass"
How would I amend the script to always have at least one random number or symbol in it?
Thank you.
You could invoke the Get-Random cmdlet three times, each time with a different input parameter (punc, digit and letters), concat the result strings and shuffle them using another Get-Random invoke:
(Get-Random -Count 15 -InputObject ([char[]]$yourPassword)) -join ''
However, why do you want to reinvent the wheel? Consider using the following GeneratePassword function:
[Reflection.Assembly]::LoadWithPartialName("System.Web")
[System.Web.Security.Membership]::GeneratePassword(15,2)
And to ensure, it contains at least one random number (you already specify the number of symbols):
do {
$pwd = [System.Web.Security.Membership]::GeneratePassword(15,2)
} until ($pwd -match '\d')
As suggested by jisaak, there is no 100% guaranty that the Membership.GeneratePassword Method generates a password that meets the AD complexity requirements.
That's why I reinvented the wheel:
Function Create-String([Int]$Size = 8, [Char[]]$CharSets = "ULNS", [Char[]]$Exclude) {
$Chars = #(); $TokenSet = #()
If (!$TokenSets) {$Global:TokenSets = #{
U = [Char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' #Upper case
L = [Char[]]'abcdefghijklmnopqrstuvwxyz' #Lower case
N = [Char[]]'0123456789' #Numerals
S = [Char[]]'!"#$%&''()*+,-./:;<=>?#[\]^_`{|}~' #Symbols
}}
$CharSets | ForEach {
$Tokens = $TokenSets."$_" | ForEach {If ($Exclude -cNotContains $_) {$_}}
If ($Tokens) {
$TokensSet += $Tokens
If ($_ -cle [Char]"Z") {$Chars += $Tokens | Get-Random} #Character sets defined in upper case are mandatory
}
}
While ($Chars.Count -lt $Size) {$Chars += $TokensSet | Get-Random}
($Chars | Sort-Object {Get-Random}) -Join "" #Mix the (mandatory) characters and output string
}; Set-Alias Create-Password Create-String -Description "Generate a random string (password)"
Usage:
The Size parameter defines the length of the password.
The CharSets parameter defines the complexity where the character U,
L, N and S stands for Uppercase, Lowercase, Numerals and Symbols.
If supplied in lowercase (u, l, n or s) the returned string
might contain any of character in the concerned character set, If
supplied in uppercase (U, L, N or S) the returned string will
contain at least one of the characters in the concerned character
set.
The Exclude parameter lets you exclude specific characters that might e.g.
lead to confusion like an alphanumeric O and a numeric 0 (zero).
Examples:
To create a password with a length of 8 characters that might contain any uppercase characters, lowercase characters and numbers:
Create-Password 8 uln
To create a password with a length of 12 characters that that contains at least one uppercase character, one lowercase character, one number and one symbol and does not contain the characters OLIoli01:
Create-Password 12 ULNS "OLIoli01"
For the latest New-Password version: use:
Install-Script -Name PowerSnippets.New-Password
Command to Generate Random passwords by using existing funciton:
[system.web.security.membership]::GeneratePassword(x,y)
x = Length of the password
y = Complexity
General Error:
Unable to find type [system.web.security.membership]. Make sure that the assembly that contains this type is loaded.
Solution:
Run the below command:
Add-Type -AssemblyName System.web;
Another solution:
function New-Password() {
param(
[int] $Length = 10,
[bool] $Upper = $true,
[bool] $Lower = $true,
[bool] $Numeric = $true,
[string] $Special
)
$upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
$lowerChars = "abcdefghijklmnopqrstuvwxyz"
$numericChars = "0123456789"
$all = ""
if ($Upper) { $all = "$all$upperChars" }
if ($Lower) { $all = "$all$lowerChars" }
if ($Numeric) { $all = "$all$numericChars" }
if ($Special -and ($special.Length -gt 0)) { $all = "$all$Special" }
$password = ""
for ($i = 0; $i -lt $Length; $i++) {
Write-Host "password: [$password]"
$password = $password + $all[$(Get-Random -Minimum 0 -Maximum $all.Length)]
}
$valid = $true
if ($Upper -and ($password.IndexOfAny($upperChars.ToCharArray()) -eq -1)) { $valid = $false }
if ($Lower -and ($password.IndexOfAny($lowerChars.ToCharArray()) -eq -1)) { $valid = $false }
if ($Numeric -and ($password.IndexOfAny($numericChars.ToCharArray()) -eq -1)) { $valid = $false }
if ($Special -and $Special.Length -gt 1 -and ($password.IndexOfAny($Special.ToCharArray()) -eq -1)) { $valid = $false }
if (-not $valid) {
$password = New-Password `
-Length $Length `
-Upper $Upper `
-Lower $Lower `
-Numeric $Numeric `
-Special $Special
}
return $password
}
Flexible enough to set length, turn on/of upper, lower, and numeric, and set the list of specials.
My take on generating passwords in PowerShell, based on what I've found here and in the Internets:
#Requires -Version 4.0
[CmdletBinding(PositionalBinding=$false)]
param (
[Parameter(
Mandatory = $false,
HelpMessage = "Minimum password length"
)]
[ValidateRange(1,[int]::MaxValue)]
[int]$MinimumLength = 24,
[Parameter(
Mandatory = $false,
HelpMessage = "Maximum password length"
)]
[ValidateRange(1,[int]::MaxValue)]
[int]$MaximumLength = 42,
[Parameter(
Mandatory = $false,
HelpMessage = "Characters which can be used in the password"
)]
[ValidateNotNullOrEmpty()]
[string]$Characters = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM##%*-_+:,.'
)
(1..(Get-Random -Minimum $MinimumLength -Maximum $MaximumLength) `
| %{ `
$Characters.GetEnumerator() | Get-Random `
}) -join ''
I preferred this over using System.Web, not to introduce dependencies, which could change with .Net / .Net Core versions.
My variation also allows random password length (in specified range), is fairly concise (apart from the parameters section, which is quite verbose, to enforce some validations and provide defaults) and allows character repetitions (as opposite to the code in the question, which never repeats the same character).
I understand, that this does not guarantee a digit in the password. This however can be addressed in different ways. E.g. as was suggested, to repeat the generation until the password matches the requirements (contains a digit). My take would be:
Generate a random password.
If it does not contain a digit (or always):
Use a random function to get 1 random digit.
Add it to the random password.
Randomize the order of the result (so the digit is not necessarily always at the end).
Assuming, that the above script would be named "Get-RandomPassword.ps1", it could look like this:
$pass = .\Get-RandomPassword.ps1
$pass += (0..9 | Get-Random)
$pass = (($pass.GetEnumerator() | Get-Random -Count $pass.Length) -join '')
Write-Output $pass
This can be generalized, to enforce using any character category:
$sets = #('abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789', '()-_=+[{]};:''",<.>/?`~')
$pass = .\Get-RandomPassword.ps1 -Characters ($sets -join '')
foreach ($set in $sets) {
$pass += ($set.GetEnumerator() | Get-Random)
}
$pass = (($pass.GetEnumerator() | Get-Random -Count $pass.Length) -join '')
Write-Output $pass
I wrote a secure password generator function in PowerShell, maybe this will be useful to someone.
Similar to the accepted answer, this script also uses Get-Random (twice), and also regular expression matching to ensure the output is secure.
The difference in this script is that the password length can also be randomised.
(To hard set a password length, just set the MinimumPasswordLength and MaximumPasswordLength values to the the same length.)
It also allows an easy to edit character set, and also has a regex to ensure a decent password has been generated with all of the following characteristics:
(?=.*\d) must contain at least one numerical character
(?=.*[a-z]) must contain at least one lowercase character
(?=.*[A-Z]) must contain at least one uppercase character
(?=.*\W) must contain at least one non-word character
The answer to your question about always including a number in your generated output can be solved by checking the output with a regex match (just use the parts of the regex that you need, based on the explanations above), the example here checks for uppercase, lowercase, and numerical:
$Regex = "(?=.*\d)(?=.*[a-z])(?=.*[A-Z])"
do {
$Password = ([string]($AllowedPasswordCharacters |
Get-Random -Count $PasswordLength) -replace ' ')
} until ($Password -cmatch $Regex)
$Password
Here is the full script:
Function GeneratePassword
{
cls
$MinimumPasswordLength = 12
$MaximumPasswordLength = 16
$PasswordLength = Get-Random -InputObject ($MinimumPasswordLength..$MaximumPasswordLength)
$AllowedPasswordCharacters = [char[]]'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?##£$%^&'
$Regex = "(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W)"
do {
$Password = ([string]($AllowedPasswordCharacters |
Get-Random -Count $PasswordLength) -replace ' ')
} until ($Password -cmatch $Regex)
$Password
}
GeneratePassword
I had the same issue here is the snippet I used to create my alphanumerical password its simple all I have done is used ASCII regex replace to make it nice.
Function Password-Generator ([int]$Length)
{
# Generate passwords just call password-generator(lenght of password)
$Assembly = Add-Type -AssemblyName System.Web
$RandomComplexPassword = [System.Web.Security.Membership]::GeneratePassword($Length,2)
$AlphaNumericalPassword = $RandomComplexPassword -replace '[^\x30-\x39\x41-\x5A\x61-\x7A]+'
Write-Output $AlphaNumericalPassword
}
I've created this. You can choose how many Pwd to create
$howoften = Read-Host "How many would you like to create: "
$i = 0
do{
(-join(1..42 | ForEach {((65..90)+(97..122)+(".") | % {[char]$_})+(0..9)+(".") | Get-Random}))
$i++
} until ($i -match $howoften)
To change the length of the pwd simply edit the "42" in line 4
(-join(1..**42** | ForEach ...
I have a script that creates a user and assigns the password and the user to a group but I need to get 2 check boxes ticked - 'User cannot change password' and 'Password never expires' but for the life of me I cannot find out how to do this.
My script so far is this:-
# Create User and add to IGNITEWEBUSERS Group
$user = $domain
# If more then 15 chars trim to just 15 chars
$user = $user.substring(0, 15)
$user = $user + "_web"
# Generate Random Complex Password
# Generate a password with 2 non-alphanumeric character.
$Length = 10
$Assembly = Add-Type -AssemblyName System.Web
$RandomComplexPassword = [System.Web.Security.Membership]::GeneratePassword($Length,2)
$password = $RandomComplexPassword
$group = 'IGNITEWEBUSERS'
$objOu = [ADSI]"WinNT://$computer"
$objUser = $objOU.Create("User", $user)
$objUser.setpassword($password)
$objUser.SetInfo()
$objUser.description = $domain + " IIS User"
$objUser.SetInfo()
$OBjOU = [ADSI]"WinNT://$computer/$group,group"
$OBjOU.Add("WinNT://$computer/$user")
That works and does what it should do but anyone know how I can set those 2 check boxes?
Various threads suggest something similar to Set-ADUser -CannotChangePassword:$true but am not using Active Directory and this doesn't work.
Your advice appreciated
Paul
Got it figured out this morning:-
$objUser.UserFlags = 64 + 65536 # ADS_UF_PASSWD_CANT_CHANGE + ADS_UF_DONT_EXPIRE_PASSWD
Set the useraccountcontrol property. You can find a list of useraccountcontrol flags here: http://support.microsoft.com/kb/305144
Add the values of the flags you want (NORMAL_ACCOUNT = 512, PASSWD_CANT_CHANGE = 64, DONT_EXPIRE_PASSWORD = 65536) for a total of 66112, and set the property to that number:
$obUser.useraccountcontrol = 66112
BTW, you only need to call the SetInfo() method once at the end, after setting all the properties you want to set.
Use WMI to get the user account:
# Use this filter so WMI doesn't spend forever talking to domain controllers.
$user = Get-WmiObject Win32_UserAccount -Filter ("Domain='{0}' and Name='{1}'" -f $env:ComputerName,$Username)
$user.PasswordChangeable = $false
$user.PasswordExpires = $false
$user.Put()
I built a script that converts .doc files to .docx.
I have a problem that when the .doc file is password-protected, I can't access it and then the script hangs.
I am looking for a way to check if the file has a password before I open it.
I using Documents.Open method to open the file.
If your script hangs on opening the document, the approach outlined in this question might help, only that in PowerShell you'd use a try..catch block instead of On Error Resume Next:
$filename = "C:\path\to\your.doc"
$wd = New-Object -COM "Word.Application"
try {
$doc = $wd.Documents.Open($filename, $null, $null, $null, "")
} catch {
Write-Host "$filename is password-protected!"
}
If you can open the file, but the content is protected, you can determine it like this:
if ( $doc.ProtectionType -ne -1 ) {
Write-Host ($doc.Name + " is password-protected.")
$doc.Close()
}
If none of these work you may have to resort to the method described in this answer. Rough translation to PowerShell (of those parts that detect encrypted documents):
$bytes = [System.IO.File]::ReadAllBytes($filename)
$prefix = [System.Text.Encoding]::Default.GetString($bytes[1..2]);
if ($prefix -eq "ÐÏ") {
# DOC 2005
if ($bytes[0x20c] -eq 0x13) { $encrypted = $true }
# DOC/XLS 2007+
$start = [System.Text.Encoding]::Default.GetString($bytes[0..2000]).Replace("\0", " ")
if ($start -like "*E n c r y p t e d P a c k a g e") { $encrypted = $true }
}
There is a technique outlined here. Essentially, you supply a fake password which files without a password will ignore; then you error-trap the ones that do require a password, and can skip them.