Antes do PowerShell 3
O Extensible Type System do PowerShell originalmente não permitia que você criasse tipos concretos que você pudesse testar da maneira como fez em seu parâmetro. Se você não precisa desse teste, está satisfeito com qualquer um dos outros métodos mencionados acima.
Se você quiser um tipo real para o qual possa lançar ou verificar o tipo, como em seu script de exemplo ... não pode ser feito sem escrever em C # ou VB.net e compilar. No PowerShell 2, você pode usar o comando "Add-Type" para fazer isso de forma bastante simples:
add-type @"
public struct contact {
public string First;
public string Last;
public string Phone;
}
"@
Nota histórica : No PowerShell 1 era ainda mais difícil. Você tinha que usar o CodeDom manualmente, há umscript de nova estrutura de função muito antigoem PoshCode.org que ajudará. Seu exemplo se torna:
New-Struct Contact @{
First=[string];
Last=[string];
Phone=[string];
}
Usar Add-Type
ou New-Struct
permitirá que você realmente teste a classe em seu param([Contact]$contact)
e faça novas usando $contact = new-object Contact
e assim por diante ...
No PowerShell 3
Se você não precisa de uma classe "real" para a qual possa lançar, você não precisa usar o método Add-Member que Steven e outros demonstraram acima.
Desde o PowerShell 2, você pode usar o parâmetro -Property para New-Object:
$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }
E no PowerShell 3, conseguimos usar o PSCustomObject
acelerador para adicionar um TypeName:
[PSCustomObject]@{
PSTypeName = "Contact"
First = $First
Last = $Last
Phone = $Phone
}
Você ainda está recebendo apenas um único objeto, então deve criar uma New-Contact
função para garantir que todos os objetos sejam iguais, mas agora você pode facilmente verificar se um parâmetro "é" um desses tipos decorando um parâmetro com o PSTypeName
atributo:
function PrintContact
{
param( [PSTypeName("Contact")]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
No PowerShell 5
No PowerShell 5 tudo muda e finalmente obtivemos class
e enum
como palavras-chave de linguagem para definir tipos (não há, struct
mas está tudo bem):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
Contact($First, $Last, $Phone) {
$this.First = $First
$this.Last = $Last
$this.Phone = $Phone
}
}
Também temos uma nova maneira de criar objetos sem usar New-Object
: [Contact]::new()
- na verdade, se você mantiver sua classe simples e não definir um construtor, você pode criar objetos lançando uma tabela de hash (embora sem um construtor, não haveria maneira para fazer com que todas as propriedades sejam definidas):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
}
$C = [Contact]@{
First = "Joel"
Last = "Bennett"
}
Add-Type
? Parece funcionar no PowerShell 2 no Win 2008 R2. Digamos que eu definemcontact
usandoAdd-Type
como na sua resposta e, em seguida, criar uma instância:$con = New-Object contact -Property @{ First="a"; Last="b"; Phone="c" }
. Então, chamar essa função funcionafunction x([contact]$c) { Write-Host ($c | Out-String) $c.GetType() }
:, mas chamar essa função falhax([doesnotexist]$c) { Write-Host ($c | Out-String) $c.GetType() }
,. A chamadax 'abc'
também falha com uma mensagem de erro apropriada sobre a transmissão. Testado em PS 2 e 4.Add-Type
@ jpmc26, o que eu disse é que você não pode fazer isso sem compilar (ou seja: sem escrever em C # e chamarAdd-Type
). Claro, no PS3 você pode - há um[PSTypeName("...")]
atributo que permite especificar o tipo como uma string, que oferece suporte a testes em PSCustomObjects com o conjunto PSTypeNames ...A criação de tipos personalizados pode ser feita no PowerShell.
Kirk Munro na verdade tem dois ótimos posts que detalham o processo completamente.
O livro Windows PowerShell In Action de Manning também contém um exemplo de código para criar uma linguagem específica de domínio para criar tipos personalizados. O livro é excelente em todos os aspectos, então eu realmente o recomendo.
Se você está apenas procurando uma maneira rápida de fazer o acima, pode criar uma função para criar o objeto personalizado, como
function New-Person() { param ($FirstName, $LastName, $Phone) $person = new-object PSObject $person | add-member -type NoteProperty -Name First -Value $FirstName $person | add-member -type NoteProperty -Name Last -Value $LastName $person | add-member -type NoteProperty -Name Phone -Value $Phone return $person }
fonte
Este é o método de atalho:
$myPerson = "" | Select-Object First,Last,Phone
fonte
$myPerson = 1 | Select First,Last,Phone
NoteProperty
destring
tipo, é umaProperty
de qualquer tipo que você atribuiu no objeto. Isso é rápido e faz o trabalho.A resposta de Steven Murawski é ótima, no entanto, gosto do mais curto (ou melhor, apenas do objeto de seleção mais limpo em vez de usar a sintaxe adicionar membro):
function New-Person() { param ($FirstName, $LastName, $Phone) $person = new-object PSObject | select-object First, Last, Phone $person.First = $FirstName $person.Last = $LastName $person.Phone = $Phone return $person }
fonte
New-Object
nem mesmo é necessário. Isso fará o mesmo:... = 1 | select-object First, Last, Phone
int
forma: 1) funciona mais rápido, não muito, mas para esta função em particularNew-Person
a diferença é de 20%; 2) é aparentemente mais fácil de digitar. Ao mesmo tempo, usando essa abordagem basicamente em todos os lugares, nunca vi nenhuma desvantagem. Mas eu concordo: pode haver alguns casos raros em que PSCustomObject é um pouco melhor.Surpreso, ninguém mencionou esta opção simples (vs 3 ou posterior) para criar objetos personalizados:
[PSCustomObject]@{ First = $First Last = $Last Phone = $Phone }
O tipo será PSCustomObject, não um tipo personalizado real. Mas provavelmente é a maneira mais fácil de criar um objeto personalizado.
fonte
Existe o conceito de PSObject e Add-Member que você pode usar.
$contact = New-Object PSObject $contact | Add-Member -memberType NoteProperty -name "First" -value "John" $contact | Add-Member -memberType NoteProperty -name "Last" -value "Doe" $contact | Add-Member -memberType NoteProperty -name "Phone" -value "123-4567"
Isso resulta como:
[8] » $contact First Last Phone ----- ---- ----- John Doe 123-4567
A outra alternativa (que eu saiba) é definir um tipo em C # / VB.NET e carregar esse assembly no PowerShell para uso direto.
Esse comportamento é definitivamente encorajado porque permite que outros scripts ou seções de seu script trabalhem com um objeto real.
fonte
Aqui está o caminho difícil para criar tipos personalizados e armazená-los em uma coleção.
$Collection = @() $Object = New-Object -TypeName PSObject $Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail') Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "John" Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe" Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "123-4567" $Collection += $Object $Object = New-Object -TypeName PSObject $Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail') Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "Jeanne" Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe" Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "765-4321" $Collection += $Object Write-Ouput -InputObject $Collection
fonte
Aqui está mais uma opção, que usa uma ideia semelhante à solução PSTypeName mencionada por Jaykul (e, portanto, também requer PSv3 ou superior).
Exemplo
Person.Types.ps1xml
:<?xml version="1.0" encoding="utf-8" ?> <Types> <Type> <Name>StackOverflow.Example.Person</Name> <Members> <ScriptMethod> <Name>Initialize</Name> <Script> Param ( [Parameter(Mandatory = $true)] [string]$GivenName , [Parameter(Mandatory = $true)] [string]$Surname ) $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName $this | Add-Member -MemberType 'NoteProperty' -Name 'Surname' -Value $Surname </Script> </ScriptMethod> <ScriptMethod> <Name>SetGivenName</Name> <Script> Param ( [Parameter(Mandatory = $true)] [string]$GivenName ) $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName -Force </Script> </ScriptMethod> <ScriptProperty> <Name>FullName</Name> <GetScriptBlock>'{0} {1}' -f $this.GivenName, $this.Surname</GetScriptBlock> </ScriptProperty> <!-- include properties under here if we don't want them to be visible by default <MemberSet> <Name>PSStandardMembers</Name> <Members> </Members> </MemberSet> --> </Members> </Type> </Types>
Update-TypeData -AppendPath .\Person.Types.ps1xml
$p = [PSCustomType]@{PSTypeName='StackOverflow.Example.Person'}
$p.Initialize('Anne', 'Droid')
$p | Format-Table -AutoSize
$p.SetGivenName('Dan')
$p | Format-Table -AutoSize
Explicação
PS1XML
ouAdd-Member
se restringem aNoteProperty
,AliasProperty
,ScriptProperty
,CodeProperty
,ScriptMethod
, eCodeMethod
(ouPropertySet
/MemberSet
; embora estes são sujeitos às mesmas restrições). Todas essas propriedades são somente leitura.ScriptMethod
, podemos enganar a restrição acima. Por exemplo, podemos definir um método (por exemploInitialize
) que cria novas propriedades, definindo seus valores para nós; garantindo assim que nosso objeto tenha todas as propriedades de que precisamos para nossos outros scripts funcionarem.SetGivenName
.Essa abordagem não é ideal para todos os cenários; mas é útil para adicionar comportamentos de classe a tipos personalizados / pode ser usado em conjunto com outros métodos mencionados nas outras respostas. Por exemplo, no mundo real eu provavelmente só definiria a
FullName
propriedade no PS1XML e, em seguida, usaria uma função para criar o objeto com os valores necessários, assim:Mais informações
Dê uma olhada na documentação ou no arquivo do tipo OOTB
Get-Content $PSHome\types.ps1xml
para se inspirar.# have something like this defined in my script so we only try to import the definition once. # the surrounding if statement may be useful if we're dot sourcing the script in an existing # session / running in ISE / something like that if (!(Get-TypeData 'StackOverflow.Example.Person')) { Update-TypeData '.\Person.Types.ps1xml' } # have a function to create my objects with all required parameters # creating them from the hash table means they're PROPERties; i.e. updatable without calling a # setter method (note: recall I said above that in this scenario I'd remove their definition # from the PS1XML) function New-SOPerson { [CmdletBinding()] [OutputType('StackOverflow.Example.Person')] Param ( [Parameter(Mandatory)] [string]$GivenName , [Parameter(Mandatory)] [string]$Surname ) ([PSCustomObject][Ordered]@{ PSTypeName = 'StackOverflow.Example.Person' GivenName = $GivenName Surname = $Surname }) } # then use my new function to generate the new object $p = New-SOPerson -GivenName 'Simon' -Surname 'Borg' # and thanks to the type magic... FullName exists :) Write-Information "$($p.FullName) was created successfully!" -InformationAction Continue
fonte