Quando o PowerShell script usando Foreach e Search-Mailbox apagam mais do que o esperado


 

Por: Eduardo Tavares de Almeida
 
Trabalhar com script em PowerShell as vezes pode causar erros inesperados. Por isso sempre recomendamos testar em um ambiente de laboratório onde seja o mais fiel possível ao de produção.
 
O PowerShell também dá opções de simular o que será feito como -WhatIf mostrando o que seria alterado, sem alterar nada.
 
Mas vamos ao exemplo que aconteceu. O administrador queria rodar um comando no PowerShell do Exchange 2010 para apagar tudo das Rooms Mailboxes que foram recebidos 1 ano atrás.
 
Então o script parecido como o exemplo abaixo foi criado, mas o resultado não foi o esperado. Um dos motivos foi que nenhuma Mailbox com aquele prefixo existia e no lugar ele foi executado para todas causando um problemão. Então ficamos com a pergunta, se a mailbox não existia, porque foi executado para todas e não para nenhuma?!?
 
Este foi o script:
 
$date = ((get-date).AddDays(-365)).ToString("M/d/yyyy")
$Rooms = Get-MailBox -Identity "Room Mailbox 5*” -ResultSize unlimited
 
Foreach ($Name in $Rooms)
{
Get-Mailbox -Identity $Name -Resultsize Unlimited | Search-Mailbox -SearchQuery  "Received:< $date" -DeleteContent -Force
}
 
Vamos entender cada parte do script para poder entender o porquê. Essa é a primeira linha:
 
$date = ((get-date).AddDays(-365)).ToString("M/d/yyyy")
 
Nessa parte ele pega a data atual e diminui 365 dias atribuindo a varável $date. Rodando o comando $date confirmamos o valor
 
image
 
 
 
Essa linha é onde começa a confusão
 
$Rooms = Get-MailBox -Identity "Room Mailbox 5*” -ResultSize unlimited
 
O esperado nesse comando seria deixar a todas as mailboxes que começam com esse nome na collection $Rooms, mas no caso dele, essa mailbox não existia. Dessa forma, ao rodar o comando get-mailbox, recebemos o erro que ela não foi encontrada:
 
[PS] C:\>$Rooms = Get-MailBox -Identity "Room Mailbox 5*" -ResultSize unlimited
The operation couldn't be performed because object 'Room Mailbox 5*' couldn't be found on 'DC01.virtual.local'.
    + CategoryInfo          : NotSpecified: (:) [Get-Mailbox], ManagementObjectNotFoundException
    + FullyQualifiedErrorId : 6D0CE178,Microsoft.Exchange.Management.RecipientTasks.GetMailbox
 
Mas então qual o valor da collection $Rooms?
Se rodarmos o comando $Rooms ele não retorna nada, isso o torna Nulo como demonstramos a seguir
 
image
              
 
 
Ok, então temos uma collection nula até o momento e novamente a pergunta, porque o comando iria rodar na próxima linha entrando no Foreach e executando o Search-Mailbox?
 
Foreach ($Name in $Rooms)
{
…….
}
 
Vamos a parte mais interessante e ver como Foreach funciona.
 
Se executarmos o comando abaixo, considerando que nunca declaramos a collection $Roomwwwwwws, vamos ver que ele irá rodar uma vez pelo menos. Esse comportamento ocorre no Exchange 2010 que usa o PowerShell 2.0
 
Foreach ($Name in $Roomwwwwwws) { Echo "Run once"}
 
image
 
 
 
 
 
 
No PowerShell 2.0, esse comportamento é padrão mas merece uma explicação. No PowerShell, o valor null é valor escalar.
Uma collection pode conter vários valores nulls, o que faria o foreach executar várias vezes
 
foreach ($i in $null,$null,$null) { } # – Executa 3 vezes
foreach ($i in $null, $null) {} # – Executa 2 vezes
foreach ($i in $null) {} # – Executa 1 vez
 
No Exchange 2013 que usa a verão 4 do PowerShell esse comportamento foi alterado e não mais será executado para valores null
 
image
 
 
 
 
Isso explica então porque o foreach foi executado a primeira vez.
 
Vamos então a linha que foi executado 1 vez dentro do foreach
 
Get-Mailbox -Identity $Name -Resultsize Unlimited | Search-Mailbox -SearchQuery  "Received:< $date" -DeleteContent -Force
 
 
Essa primeira parte é a que mais interessa Get-Mailbox -Identity $Name. Como a collection está com valor nula, em vez de retornar erro dizendo que ele não encontrou a mailbox, o que o PowerShell faz é desconsiderar o parâmetro Identity, então nesse caso seria o mesmo que executar Get-Mailbox. Como o retorno desse comando irá buscar todas mailboxes, o resultado para p próximo comando será a deleção em todas mailboxes causando então o transtorno.
 
O comando Search-Mailbox também tem o parâmetro -LogOnly que irá ajudar a verificar todas mailboxes que seriam afetas antes de qualquer alteração.
 
 
 
 
Comments (0)

Skip to main content